Faire
Faire

Reputation: 1021

ReactJS: Change state of child component

I have parent component, which contains a global value in its state. Change of this value must trigger change of states of children components as in following example:

function Parent(props) {
const [parentState, setParentState] = useState(someState);

return (
  <button onClick={() => setParentState(newState)>Button</button>
  <ChildComponent parentState={parentState} />
}

function Child(props) {
const [childState, setChildState] = useState(getState(props.parentState));
}

Click on the button in this example should change trigger non-trivial change of the state in the Child component (which uses parentState as a parameter to generate its own state).

I guess the first answer to the problem would be to lift the state up - however I would like not to do that, because there are many Child generated through a .map function - I would need to retain their states in an array and propagate it to all the child components. The value in the parent component is a global value relevant for all the children and all the children must change their states when the parentState changes.

Is there any good way to achieve that without lifting the Child components' states? I hope I have described the problem well enough - if not I will be glad to update the information.

Upvotes: 2

Views: 6246

Answers (3)

WGriffing
WGriffing

Reputation: 634

Based on your clarifying comment, here's some ideas on how to proceed. Depending on what a parentState object contains, there might better ways to do this, but hopefully it will help spur some ideas.

  1. Use parentState in 2 ways.
    1. As a Child prop. This will always be updated whenever the Parent changes its value.
    2. As the initial value of one of the Child's useState hooks. This will initialize the child's derivative state, but will allow the Child state to deviate over time based on user actions within the Child component.
  2. Use useEffect hook(s) to trigger your Child getData function when the parentState variable changes or when the childStateSettings variable changes.
  3. Use multiple useState hooks in Child to separate the non-derivative part of the state from the inherited/derivative part of the Child's state. For the derivative state, childStateSettings, use parentState as the initial value.

So the Child becomes something like:

import { useEffect, useState } from 'react';

function Child(props) {
  const { parentState } = props;

  // initial value of child settings from parent
  const [childStateSettings, setChildStateSettings] = useState(parentState); 

  // non-inherited/non-derivative state of child
  const [childStateData, setChildStateData] = useState({}); 

  // Depending on the number of settings and ways in which
  //  the user can make them different than the parent/global settings,
  //  you may want to have even more useState hooks to further separate
  //  the settings into individual pieces. I think this would simplify
  //  your various `onChange`/`onSelection'/etc. function logic, but I
  //  couldn't say for certain without more details.


  useEffect(() => {
    getData(childStateDerivative, childStateNonDerivative);
  }, [parentState, childStateSettings]};

  // pseudocode invented by me as a guess of 
  //  how you might need to use things based on your comment
  const getData = (parentState, childState) => {
    // last spread object takes precedence if duplicate keys are present in both objects
    const combinedState = { ...parentState, ...childState }; 
    API.get('http://some_path', combinedState).then(data => {
      setChildStateData(data);
    });
  };

  // you'll probably draw some inputs so that the 
  //  user can alter the child's state settings but
  //  I didn't bother trying to guess what that might look like.
  return (<>...</>); 

}

Upvotes: 4

Geoff
Geoff

Reputation: 309

When you change the parent state the child will redraw. You can use setState() in the constructor to modify your child state while it is being recreated in the DOM.

Upvotes: 0

kooskoos
kooskoos

Reputation: 4879

Child should not have a state of of it's own. It should completely depend on parent state/props.

function Parent(props) {
const [parentState, setParentState] = useState(someState);

return (
  <button onClick={() => setParentState(newState)>Button</button>
  <ChildComponent parentState={parentState} />
}

function Child(props) {
}

Upvotes: 1

Related Questions