'How to communicate between sibling components in React
How to transfer props from one sibling to another, please?
In main app I have only 2 siblings:
Input:
import React from "react";
const Input = () => {
return (
<>
<label htmlFor="name">Full Name</label>
<input type="text" id="name" placeholder="TheDareback" />
<label htmlFor="job">Job Title</label>
<input type="text" id="job" placeholder="Frontend Developer" />
</>
);
};
export default inputDetails;
Preview:
import React from "react";
const Preview = () => {
return (
<>
<table>
<thead>
<tr>
<th>{/* here I need a Full Name from the input */}</th>
<th>{/* here I need a Job Title from the input*/}</th>
</tr>
</thead>
</table>
</>
);
};
export default Preview;
I tried to add useEffect to Preview to read the value of each input.
for example
const name = document.querySelector("#name");
const [inputName, setInputName] = useState("TheDareback");
useEffect(() => (name.value ? setInputName(name.value) : null));
But I'm still getting an error:
Preview.js:9 Uncaught TypeError: Cannot read properties of null (reading 'value')
Is it possible to run useEffect only during the second rendering? Alternatively, is there another option than to move the props directly from Input.js where would I create a handler for each onChange in input?
Thank you very much for heading in the right direction.
Solution 1:[1]
Keep the state in the App component and give setter to Input and state to Preview component.
App.js
import Input from "./Input";
import Preview from "./Preview";
export default function App() {
const [state, setState] = useState({ name: "", job: "" });
return (
<div className="App">
<Input setState={setState} />
<Preview state={state} />
</div>
);
}
Input.js
import React from "react";
const Input = ({ setState }) => {
const onChangeHandler = (e) => {
setState((prevState) => ({
...prevState,
[e.target.id]: e.target.value
}));
};
return (
<>
<label htmlFor="name">Full Name</label>
<input
type="text"
id="name"
placeholder="TheDareback"
onChange={onChangeHandler}
/>
<label htmlFor="job">Job Title</label>
<input
type="text"
id="job"
placeholder="Frontend Developer"
onChange={onChangeHandler}
/>
</>
);
};
export default Input;
Preview.js
import React from "react";
const Preview = ({ state: { name, job } }) => {
return (
<>
<table>
<thead>
<tr>
<th>{name}</th>
<th>{job}</th>
</tr>
</thead>
</table>
</>
);
};
export default Preview;
Solution 2:[2]
You need some sort of a container component (or App.js for example), you can have an input state there, and an inputHandler function to pass to the Input component and put it with an onChange for example.
import React, {useState} from 'react';
export default function Container() {
const [input, setInput] = useState({
name: '',
job: ''
})
const inputHandler = (e, type) => {
setInput(prevState => ({...prevState, [type]: e.target.value}))
}
return (
<>
<Input onInputChange={inputHandler} />
<Preview input={input} />
</>
);
}
Input:
const Input = ({onInputChange}) => {
return (
<>
<label htmlFor="name">Full Name</label>
<input type="text" id="name" placeholder="TheDareback" onChange={(e) => onInputChange(e, 'name')} />
<label htmlFor="job">Job Title</label>
<input type="text" id="job" placeholder="Frontend Developer" onChange={(e) => onInputChange(e, 'job')} />
</>
);
};
export default Input;
Preview:
const Preview = ({input}) => {
return (
<>
<table>
<thead>
<tr>
<th>{input.name}</th>
<th>{input.job}</th>
</tr>
</thead>
</table>
</>
);
};
export default Preview;
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 | Amila Senadheera |
| Solution 2 |
