Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
298 views
in Technique[技术] by (71.8m points)

reactjs - React Child is updating Parent State when manipulating the props in child. Unwanted

The below code is live at https://codesandbox.io/s/child-updating-parent-dont-want-pfdxd The issue I am facing is that when I sort on child component(page2), it also updates state on the parent component(App). I want to avoid state update as the other child component(page 1) should display the unsorted data. I thought about having two states with the same data(two names and two numbers) on App.js. Then use 1 set of states(name and numbers)for page 1 and the other set for page2.This seems redundant and unnecessary but I am not sure how to avoid the state update when sorting on page 2. Is there a way to avoid the state update when manipulating the data in the child component?

/*Parent*/  
    class App extends React.Component {
      constructor() {
        super();
        this.state = {
          numbers: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10],
          names: ["john", "sally", "bill", "rebecca"]
        };
      }
      render() {
        const { numbers, names } = this.state;
        return (
          <Router>
            <div className="App">
              <Header />
              <Switch>
                <Route
                  path="/page1"
                  exact
                  render={(routeProps) => (
                    <Page1 digits={numbers} people={names} {...routeProps} />
                  )}
                />
                <Route
                  path="/page2"
                  exact
                  render={(routeProps) => (
                    <Page2 digits={numbers} people={names} {...routeProps} />
                  )}
                />
              </Switch>
            </div>
          </Router>
        );
      }
    }
    export default App;

Here is the first component that receives the props

/*child 1*/
const page1 = ({ people, digits }) => {
  return (
    <div>
      <h1>
        Number Should Be "1" And Name Should Be "john" On This Page Regardless
        Of Sort On Page 2
      </h1>

      <p>Number: {digits[0]}</p>
      <p>Name: {people[0]}</p>
    </div>
  );
};
export default page1;

Here is the second component that receives the props

/*child 2*/

    const Page2 = ({ people, digits }) => {
      /* when uncommented the sort will also change state on App.js --- 
      I want state on App.js to remain in original state aft sorting*/
    
      /* --- UNCOMMENT BELOW TO SORT --- */
    
      /*people.sort((a, b) => b.toLowerCase().localeCompare(a.toLowerCase()));
      digits.sort((a,b)=>b-a)*/
    
      return (
        <div>
          <h1>
            Number Should Be "10" And Name Should Be "sally" On This Page When Sort
            Is Uncommented
          </h1>
          <p>Number: {digits[0]}</p>
          <p>Name: {people[0]}</p>
        </div>
      );
    };
    export default Page2;
question from:https://stackoverflow.com/questions/66057096/react-child-is-updating-parent-state-when-manipulating-the-props-in-child-unwan

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

In Javascript, sort method performs in-place sorting. So, when you are performing people.sort, you actually end up modifying the passed people prop. Since arrays are passed by reference, every other reference of people will show up the new sorted value.

To fix this, You should mutate a local copy of the passed prop to prevent such unexpected outcomes.

const Page2 = ({ people, digits }) => {

  const sortedPeople = [...people].sort((a, b) => b.toLowerCase().localeCompare(a.toLowerCase()))
  
  const sortedDigits = [...digits].sort((a,b)=>b-a);

  return (
    <div>
      <h1>
        Number Should Be "10" And Name Should Be "sally" On This Page When Sort
        Is Uncommented
      </h1>
      <p>Number: {sortedDigits[0]}</p>
      <p>Name: {sortedPeople[0]}</p>
    </div>
  );
};
export default Page2;

To further explain whats going on in the above approach,

Instead of directly mutating the prop, we are now creating a copy of the array, in this case people and digits by using a ES6 spread operator like this [...people] and sorting on this new copy.

const sortedPeople = [...people].sort((a, b) => b.toLowerCase().localeCompare(a.toLowerCase()))

PS. You can also do Array.from(people) or people.slice() to achieve the same result.

Keep in mind, you can further optimise the rendering performance of this in React by using a useMemo hook and do something like this

const sortedPeople = useMemo(() => [...people].sort((a, b) => b.toLowerCase().localeCompare(a.toLowerCase())), [people]);

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...