简体   繁体   English

当状态相同时,为什么 React 会重新渲染组件?

[英]Why is React rerendering the component when the states are the same?

I have an object state inside my react component set up like this:我的反应组件中有一个object state 设置如下:

const [state, setState] = useState({ keyOne: true, keyTwo: 'someKey' })

When I change the state, the component obviously rerenders.当我更改 state 时,组件显然会重新渲染。 But that's the problem.但这就是问题所在。 The component is rerendering even if I change the state to the value that it's currently set to.即使我将 state 更改为当前设置的值,该组件仍在重新渲染。 For example, the component still rerenders if I do this:例如,如果我这样做,组件仍然会重新渲染:

setState({ keyOne: true, keyTwo: 'someKey' });

I'm guessing this is because I'm passing a new object to setState , and so it will be interpreted as a different state each time even if the content in the object is the same.我猜这是因为我将新的 object 传递给setState ,因此即使 object 中的内容相同,每次它都会被解释为不同的 state So I guess my question is:所以我想我的问题是:

How can I prevent a component from re-rendering if the new object state has the same content as the original state?如果新的 object state 与原始 state 具有相同的内容,如何防止组件重新渲染? Is there a built-in way to do this, or will I have to compare the objects beforehand myself?有没有内置的方法可以做到这一点,还是我必须自己事先比较对象?

It's rerendering because the new object is a different object from the previous object.它正在重新渲染,因为新的 object 与之前的 object 不同。 It may have all the same properties inside of it, but react only does a shallow comparison.它内部可能具有所有相同的属性,但 react 只进行了浅显的比较。

If you want to skip the render, you will need to make sure the object reference does not change.如果你想跳过渲染,你需要确保 object 参考没有改变。 For example:例如:

setState(prev => {
  if (prev.keyOne === true && prev.keyTwo === 'someKey')  {
    return prev; // Same object, so render is skipped
  } else {
    return { keyOne: true, keyTwo: 'someKey' };
  }
});

If you have some favorite library for checking deep equality (Eg, lodash or ramda ), you could shorten it to something like the following.如果您有一些最喜欢的用于检查深度相等的库(例如lodashramda ),您可以将其缩短为如下所示。 This will be particularly useful if there are a lot of properties you would otherwise need to check:如果您需要检查很多属性,这将特别有用:

setState(prev => {
  const next = { keyOne: true, keyTwo: 'someKey' };
  return R.equals(prev, next) ? prev : next;
});

One option is to use separate states for the different properties of the object.一种选择是为 object 的不同属性使用单独的状态。 That way, a re-render will only be triggered once one of the new state values is different.这样,只有在新的 state 值之一不同时才会触发重新渲染。 For a small example:举个小例子:

 const App = () => { console.log('rendering'); const [val, setVal] = React.useState(true); React.useEffect(() => { setVal(true); }, []); return 'foo'; }; ReactDOM.createRoot(document.querySelector('.react')).render(<App />);
 <script crossorigin src="https://unpkg.com/react@18/umd/react.development.js"></script> <script crossorigin src="https://unpkg.com/react-dom@18/umd/react-dom.development.js"></script> <div class='react'></div>

As you can see, despite the state setter being called, the component doesn't re-render, because the new state is the same as the old state.如您所见,尽管调用了 state 设置器,但组件不会重新渲染,因为新的 state 与旧的 state 相同。

For your code, you'd have something like对于你的代码,你会有类似的东西

const [keyOne, setKeyOne] = useState(true);
const [keyTwo, setKeyTwo] = useState('someKey');

Using an approach like the above instead of putting state into a single object is a very common practice with functional components.使用上述方法而不是将 state 放入单个 object 是功能组件的一种非常常见的做法。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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