父状态更改时,组件将卸载

时间:2019-04-10 07:21:44

标签: reactjs react-hooks

我正在使用React 16.8.2,并且每当应用程序组件中的状态发生更改时,我的组件子项就无法卸载。

这是场景:

  • 我有带有许多状态变量(useState)的App.jsx(功能组件)
  • 其中一些状态变量的设置器通过Context提供程序(后代中的useContext)传递到树上
  • 我有一个菜单组件(app的后代),它调用这些设置器以(例如)显示模式对话框
  • 我有一个模式对话框组件(App的子组件),它使用状态变量作为属性来确定它是否打开-我认为是标准的React东西。

我的问题:当更改App中的任何状态变量(当然是通过钩子)时,App的子级将被卸载并重新装载-即使它们与要更改的状态没有任何关系。它们不只是被重新渲染-子代被卸载并且它们的状态被重新初始化。因此,例如在不应该显示的字段中,这些字段会在我的对话框中清除。

这已经是一个相当复杂的应用程序,所以我今天花了很多时间来解决问题。然后,我设置了一个简单的create-react-app,尝试在此复制此行为-但此测试应用的行为与预期相同。更改父状态,无论是通过prop回调,还是通过子级通过上下文提供的回调-重新渲染,但不会卸载/重新装入,子状态保持不变。

但是在我的真实应用程序中,组件重新安装并且子状态重新初始化。

我已将其简化到最低限度-我正在子级中通过Context通过“ setFoo”设置一个伪状态变量“ foo”。即使任何组件都没有使用foo,更改foo的值也会导致App的子代卸载/重新装载。

在App.jsx中:

const App = props => {
  const [foo, setFoo] = useState(false);
  // ...
  const appControl = {
    toggleFoo: () => setFoo(!foo);
  };
  // ...
  return (
    <AppContext.Provider value={appControl}>
      ... a bunch of stuff not using foo anywhere
      ... including, deep down:
      <Menu />
    </AppContext.Provider>
  );
};

在Menu.jsx中:

const Menu = props => {
  const appControl = useContext(AppContext);
  // ...
  return (
    ... super simplified for test
    <div onClick={appControl.toggleFoo}>
      Toggle Foo
    </div>
  );
};

如果我正确理解状态,那么我确实相信更改状态应该导致重新渲染孩子,而不是重新安装孩子。这是我在简单的create-react-app测试中看到的,但在我的真实应用中却没有。

我确实发现我没有使用最新的React-也许升级会解决这个问题?

感谢您对我可能在这里做错的事情或误解了任何见解。

1 个答案:

答案 0 :(得分:0)

已解决。这是一个有趣的。这是发生了什么。

在我的App组件中,我有一棵相当深的HOC树。由于我的一些可疑决定,我最终将App分为两个部分。 App和AppCore。我有一个理由,它似乎在凌晨3点有意义。但是为了既快速又肮脏,我将AppCore作为常量添加到了我的App函数中。我记得自己在想:“我想知道这将引起什么问题?”现在我知道了。不过,也许React专家可以向我完全解释这一点,因为我看不到分配给常量的JSX与直接返回的JSX之间的区别。但这显然很容易复制。

要复制,请创建一个测试应用程序,然后将其创建:

<div id="send" onchange="capitalizestring()">bank transfer</div>
<div id="send" oncclick="capitalizestring()">bank transfer</div>
<script>capitalizestring();</script>

然后将App.js的内容替换为:

create-react-app test
cd test

然后启动npm,然后单击“ Toggle Foo”,您将看到Test组件已卸载/重新安装。

此处的解决方案是将AppCore移出功能主体。在我的真实应用中,这意味着我要进行一些重构。

我想知道这是否会被视为一个React问题?