在 setState 挂钩中更改 prev 状态更新视图,而无需重新呈现。为什么?

我的更改产品名称函数称为 setState,它返回“突变的上一个状态”。我将函数传递给子组件,并通过上下文 API 在子组件中调用它。该函数已成功更新了子级和父级中显示的产品名称,但父级确实触发了重新渲染。父级如何在不重新渲染的情况下更新视图?谁能解释一下设置状态中的上一个状态实际上是什么?


const App = () => {

  const [products, setProducts] = useState(initialValues);


  const changeProductName = (id, newName) => {

    setProducts((prevState) => {   //is preState a copy of state?  

      prevState.products.filter(

        (product) => product.id === id 

      )[0].name = newName;        //Mutates prevState

      return prevState;           //Did I return a new state?

    });

  };


  useEffect(() => 

    console.log("I would know when App re-renders")); //No re-render!


  return (

    <>    //Some React Switch and Routers 

    <div>

      {product.map(product=>product.name)}   //Successfully Updated!

    </div>

    <ProductContext value={(products, changeProductName)}> 

      <ProductPage />     //call changeProductName and it works!

    </ProductContext>

    </>   

  ); 

};


如果我更改的函数不触及 prevState,父级将按预期重新呈现。这种方法更好吗?


  //this will trigger parent re-render.

  const changeProductName = (id, newName) => { 

    setProducts((prevState) => {

      prevState.products.filter(

        (product) => product.id === id

      )[0].name = newName;

      return prevState;

    });

  };


繁星点点滴滴
浏览 83回答 2
2回答

慕田峪7331174

据我所知,改变国家通常是一个坏主意。根据这个答案,改变状态可能不会导致重新渲染,因为在突变过程中对状态对象的引用不会改变。我宁愿使用某种类似 redux 的不可变模式:const changeProductName = (id, newName) => {&nbsp;&nbsp; setProducts((prevState) => (&nbsp; &nbsp; prevState.map(product=>{&nbsp; &nbsp; &nbsp; if(product.id!==id){&nbsp; &nbsp; &nbsp; &nbsp; // name is not changed since the id does not match&nbsp; &nbsp; &nbsp; &nbsp; return product;&nbsp; &nbsp; &nbsp; } else {&nbsp; &nbsp; &nbsp; &nbsp; // change it in the case of match&nbsp; &nbsp; &nbsp; &nbsp; return {...product, name:newName}&nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; }&nbsp; )}

红糖糍粑

谁能解释一下设置状态中的上一个状态实际上是什么?prev 状态是对前一个状态的引用。它不是状态的副本,它是位于状态内部的对象的引用。因此,更改该对象不会更改对象引用。因此,它不应该直接突变。相反,应通过基于 prevState 的输入构建新对象来表示更改。例如,如果您在更改中进行检查,例如:setProducts(prevState => {&nbsp; prevState.filter(product => product.id == id)[0].name = newName;&nbsp; console.log(prevState === products); // This will console true&nbsp; return prevState;});&nbsp;另外,由于您正在使用钩子,因此当您编写...本身已经是产品了。因此,当您尝试访问 时,您将在示例中得到未定义的错误。setProducts((prevState) => { prevState.products}prevState.products所以我建议你这样做:&nbsp; const changeProductName = (id, newName) => {&nbsp; &nbsp; setProducts(prevProducts =>&nbsp; &nbsp; &nbsp; prevProducts.map(product =>&nbsp; &nbsp; &nbsp; &nbsp; product.id === id ? { ...product, name: newName } : product&nbsp; &nbsp; &nbsp; )&nbsp; &nbsp; );&nbsp; };.map将基于 prevState 构建一个新数组,并更改在函数中调用 ID 的产品的名称。
打开App,查看更多内容
随时随地看视频慕课网APP

相关分类

Java
JavaScript