Reputation: 934
We can pass a callback to a child as props and update the state but I was just wondering can I pass useState setter to the child and call it directly in child to update parents state?
Something like:
function Parent(){
const [data, setData] = useState();
return(
<Child setData={setData}/>
);
}
function Child({setData}){
useEffect(()=>{
setData('new data'); //Calling setter here to update
}, [])
}
Upvotes: 27
Views: 17596
Reputation: 157
Yes, that is perfectly ok. You can also utilize useContext() (global variables/functions) and even consider using an HOC in the future if you'll be working with many hooks. Then you can centralize all of the hooks to one component and re-use them throughout your application.
For an HOC some common use cases from my past projects are:
Upvotes: 1
Reputation: 1062
Yes, you can do that. In fact, it is good practice to do that. To avoid unnecessary re-renders and infinite loops, either include setData
in the dependency array of the Child's useEffect
or wrap the data
in a useCallback
in the Parent component. Also, it is recommended to initialise the data to some initial value when using useState
. In your case, I would initialise it to null
-> const [data, setData] = useState(null)
Example with the dependency array:
function Child({ setData }) {
useEffect(() => {
setData("new data"); //Calling setter here to update
}, [setData]);
return (...);
}
If you want to pass it to a child that is multiple levels deep, I would suggest using Context. With context, you can then use the useState
in any child and you don't need to pass it as props throughout all of the children between the Parent
and the Child
that you want to use it in.
Example with the Context:
// Step 1. Create context
const MyContext = React.createContext();
// Step 2. Create a custom hook that will return Context
// This will allow you to use the context in any number of children more easily.
// And it will also make sure that it is only used within Parent component
const useData = () => {
const context = React.useContext(MyContext);
if (!context) {
throw new Error("useData must be used within a <Parent />");
}
return context;
};
function Parent() {
const [data, setData] = useState(null);
const value = [data, setData];
// Step 3. Use Context Provider and pass the value of the props that
// need to be used by any children down the tree
return (
<MyContext.Provider value={value}>
<Child />
</MyContext.Provider>
);
}
function Child() {
return <ChildTwo />;
}
function ChildTwo() {
// Step 4. Extract the prop from the Context that you need using custom hook
const [data, setData] = useData();
useEffect(() => {
setData("new data"); //Calling setter here to update
}, [setData]);
return (...);
}
Upvotes: 20