简体   繁体   中英

Child component not updating with updates state via Parent props

I have a parent component from where I am passing a callback function handleProjectStagesSave and some data as props to child component. In my child component, I am accessing the props and storing the props object as a whole to the state using useState .

Parent component:

function ProjectStages(props) {
    const [projectStages, setProjectStages] = React.useState(null);

    useEffect(() => {
          ProjectAPI.getProjectStages().then((response) => {
            setProjectStages(response);
          });
    }, []);

    //this function is passed as prop to child component. child component send data through parameters back to parent
    function handleProjectStagesSave(val){     
      projectStages.someProperty = val;  //modifying state property here and updating the state below
      setProjectStages(projectStages);
    }

    if(projectStages === null){
      return (<Loader/>);
    }

    return (
      <div>
        {(() => {
           //loop through state data and pass props to child component
          return projectStages.phases.map((stage) => {
            return (
                <ProjectStageTile criterias={stage.criterias} stagesSave={handleProjectStagesSave}/>
            );
          });
        })()}
      </div>
    );
}

Now, the child component passes the callback function to it's own child component CriteriaScores which basically passes some data and sends it back all the way up to the parent.

Child component:

function ProjectStageTile(props){
    const [projectStageTileState, setProjectStageTileState] = React.useState(props);

    return projectStageTileState.criterias.map((criteria) => {

        return(
            <div>
                <div>
                    {criteria.selectedScore}
                </div>
                <CriteriaScores stagesSave={projectStageTileState.stagesSave} />
            </div>
        );
    });
}

It works fine and I get the data and store update the state setProjectStages(projectStages); in parent component. Now, I expect the child component to have the updated state data immediately. However, what I saw in React dev tools is that, after updating the state, I update the props in the child component manually, then the state changes are reflected in the Child component. Any idea what is wrong? Please let me know if I can clarify more on this.

Update-1:

Instead of mutating the state directly I tried something like below but got same result.

projectStages.phases.filter((phase) => (phase.gdfatStage === "bid"))[0].criterias
      .filter((criteria) => (criteria.criteriaId === val.split(' ')[1]))[0].selectedScore = val.split(' ')[2];
let newProjectStages = projectStages;
setProjectStages(newProjectStages);

Update-2:

Also tried below approach but it did not work.

let newProjectStages = projectStages;

newProjectStages.phases.filter((phase) => (phase.gdfatStage === "bid"))[0].criterias
.filter((criteria) => (criteria.criteriaId === val.split(' ')[1]))[0].selectedScore = val.split(' ')[2];

setProjectStages(newProjectStages);

projectStages is a state variable, and you are mutating it directly.

projectStages.someProperty = val; 

The recommended way of doing this is as follows:

setProjectStages(...projectStages, someProperty : val)

When you use setProjectStages react will re-render, and the most recent state variable will be passed to the child component.

In addition to the answer provided by @user9408899, I would add that the child component does not need to store its props in state. I would change it to:

function ProjectStageTile(props){
    const {criteria, stagesSave} = props;

    return criterias.map((criteria) => {
        return(
            <div>
                <div>
                    {criteria.selectedScore}
                </div>
                <CriteriaScores stagesSave={stagesSave} />
            </div>
        );
    });
}

This worked:

const newProjectStages = Object.assign({}, projectStages); //this is important

newProjectStages.phases.filter((phase) => (phase.gdfatStage === "bid"))[0].criterias
.filter((criteria) => (criteria.criteriaId === val.split(' ')[1]))[0].selectedScore = val.split(' ')[2];

setProjectStages(newProjectStages);

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM