Reputation: 1021
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
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.
parentState
in 2 ways.
Child
prop. This will always be updated whenever the Parent
changes its value.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. useEffect
hook(s) to trigger your Child
getData function when the parentState
variable changes or when the childStateSettings
variable changes.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
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
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