React Child 在操作 child 中的道具时正在更新 Parent State。不需要的
React Child is updating Parent State when manipulating the props in child. Unwanted
以下代码已在 https://codesandbox.io/s/child-updating-parent-dont-want-pfdxd 上线
我面临的问题是,当我对子组件 (page2) 进行排序时,它还会更新父组件 (App) 的状态。我想避免状态更新,因为另一个子组件(第 1 页)应该显示未排序的数据。我考虑过在 App.js 上有两个具有相同数据(两个名字和两个数字)的州。然后为第 1 页使用一组状态(名称和数字),为 page2.This 使用另一组状态似乎是多余和不必要的,但我不确定在第 2 页上排序时如何避免状态更新。有没有办法在子组件中操作数据时避免状态更新?
/*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;
这是接收道具的第一个组件
/*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;
这是接收道具的第二个组件
/*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;
在Javascript中,sort
方法执行就地排序。因此,当您执行 people.sort
时,您实际上最终修改了传递的 people
道具。由于数组是通过引用传递的,因此 people
的所有其他引用都将显示新的排序值。
要解决此问题,您应该改变传递的 prop 的本地副本以防止此类意外结果。
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;
为了进一步解释上述方法的原理,
我们现在不是直接改变 prop,而是创建数组的副本,在本例中是 people
和 digits
通过使用像这样的 ES6 扩展运算符 [...people]
和在这个新副本上排序。
const sortedPeople = [...people].sort((a, b) => b.toLowerCase().localeCompare(a.toLowerCase()))
PS。您也可以执行 Array.from(people)
或 people.slice()
以获得相同的结果。
请记住,您可以使用 useMemo
挂钩进一步优化 React 中的渲染性能,并执行类似的操作
const sortedPeople = useMemo(() => [...people].sort((a, b) => b.toLowerCase().localeCompare(a.toLowerCase())), [people]);
以下代码已在 https://codesandbox.io/s/child-updating-parent-dont-want-pfdxd 上线 我面临的问题是,当我对子组件 (page2) 进行排序时,它还会更新父组件 (App) 的状态。我想避免状态更新,因为另一个子组件(第 1 页)应该显示未排序的数据。我考虑过在 App.js 上有两个具有相同数据(两个名字和两个数字)的州。然后为第 1 页使用一组状态(名称和数字),为 page2.This 使用另一组状态似乎是多余和不必要的,但我不确定在第 2 页上排序时如何避免状态更新。有没有办法在子组件中操作数据时避免状态更新?
/*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;
这是接收道具的第一个组件
/*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;
这是接收道具的第二个组件
/*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;
在Javascript中,sort
方法执行就地排序。因此,当您执行 people.sort
时,您实际上最终修改了传递的 people
道具。由于数组是通过引用传递的,因此 people
的所有其他引用都将显示新的排序值。
要解决此问题,您应该改变传递的 prop 的本地副本以防止此类意外结果。
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;
为了进一步解释上述方法的原理,
我们现在不是直接改变 prop,而是创建数组的副本,在本例中是 people
和 digits
通过使用像这样的 ES6 扩展运算符 [...people]
和在这个新副本上排序。
const sortedPeople = [...people].sort((a, b) => b.toLowerCase().localeCompare(a.toLowerCase()))
PS。您也可以执行 Array.from(people)
或 people.slice()
以获得相同的结果。
请记住,您可以使用 useMemo
挂钩进一步优化 React 中的渲染性能,并执行类似的操作
const sortedPeople = useMemo(() => [...people].sort((a, b) => b.toLowerCase().localeCompare(a.toLowerCase())), [people]);