Madhur Bansal
Madhur Bansal

Reputation: 934

Is it a correct approach to pass useState setter to a child for updating parents state?

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

Answers (2)

Kota
Kota

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:

  • Errors
  • Validation
  • Authentication

Upvotes: 1

Mantas Astra
Mantas Astra

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

Related Questions