首页 > 解决方案 > 在 setState 钩子中改变 prevState 更新视图而不重新渲染。为什么?

问题描述

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

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;
    });
  };

标签: javascriptreactjs

解决方案


据我所知,改变状态通常是一个坏主意。

根据这个答案,改变状态可能不会导致重新渲染,因为在突变期间对状态对象的引用没有改变。

我宁愿使用某种类似 redux 的不可变模式:

const changeProductName = (id, newName) => { 
  setProducts((prevState) => (
    prevState.map(product=>{
      if(product.id!==id){
        // name is not changed since the id does not match
        return product;
      } else {
        // change it in the case of match
        return {...product, name:newName}
      }
    }
  )
}

推荐阅读