当我更改不相关的状态时,为什么我的所有组件都重新呈现?

Why are all my component rerendering when I change an unrelated state?

我正在尝试在不重新加载整个应用程序的情况下更改状态。由于某种原因,这并没有发生,当我设置一个甚至没有传递给特定组件的对象的状态时,该组件就会无缘无故地更新。

所以在下面的代码中,我在设置消息时,MainContent 不应该重新加载。

const [message, setMessage] = useState({});
setMessage('my message'); // This causes the entire app, including 'MyComponent' to reload

return (
    <div className='App'>
        <Header user={user} message={message} setMessage={setMessage} />

        <div id='main-site'>
            <Switch>
                // SHOULD NOT RELOAD UNLESS PASSED IN PROP CHANGED
                <Route path='/main' component={MainContent} />

            </Switch>
        </div>
    </div>
);

Header.jsx

return (
    {message && (
        <div>
            <span>{message.text}</span>
            // This on click makes the entire app reload
            <button className='close' onClick={() => setMessage({})}>
                X
            </button>
        </div>
    )}
);

如何确保只有具有 message 属性的组件得到更新,而没有其他组件重新渲染?

您应该将钩子定义到组件函数中。绑定变量,它 setMessage 仅更新函数到该组件。 在 React 中,更新 dom 的唯一方法是调用 React.Component 上的所有纯组件或 render 函数,并将 return 与之前的 return 进行比较。

因此,在通过 SetMessage 响应更改视图后更新视图,再次调用所有渲染函数来更新视图。

function MyComponet(){
  return (
    <div className='App'>
        <Header user={user} message={'my message'} />

        <div id='main-site'>
            <Switch>
                // SHOULD NOT RELOAD UNLESS PASSED IN PROP CHANGED
                <Route path='/main' component={MainContent} />

            </Switch>
        </div>
    </div>
);
}


//state that updating when props updating too
function usePropsState(initialState) {
  const [state, setState] = useState(initialState);
  useEffect(() => setState(initialState), [initialState]);
  return [state, setState]
}

function Header({user, message:initMessage}){
  // now you can update the state internally or from outside
  const [message, setMessage] = usePropsState(initMessage);
  return (
    {message && (
        <div>
            <span>{message}</span>
            // This on click makes the entire app reload
            <button className='close' onClick={() => setMessage('')}>
                X
            </button>
        </div>
    )}
  );
}

如果你喜欢那个自定义挂钩,请顶起this问题

有两种方法可以解决您的问题。

第一个涉及将您的状态向下移动到 Child 组件,即 Header,因为只有 Header 使用 message 状态。另一件要记住的事情是,你不要在渲染中直接调用状态更新器,因为它会继续调用反应状态更新器,尽管它不会影响你的应用程序,因为如果相同的状态是反应内部阻止 re-render再次提供给状态更新器。

const [message, setMessage] = useState({});
setMessage('my message');

return (
    {message && (
        <div>
            <span>{message.text}</span>
            // This on click makes the entire app reload
            <button className='close' onClick={() => setMessage({})}>
                X
            </button>
        </div>
    )}
);

当您必须将消息传递给多个组件时,第二种更可靠的方法是对组件使用 React.memo

const MyComponent = () => (
   ...
);

export default React.memo(MyComponent)