Eri*_*c S 13 reactjs react-hooks
我正在使用 React 16.8.2,并且每当应用程序组件中的状态发生更改时,我的组件的子组件都会卸载。
这是场景:
我的问题:当 App 中的任何状态变量发生更改时(当然是通过钩子),App 的子项将被卸载并重新安装 - 即使它们与正在更改的状态没有任何联系。它们不仅仅是重新渲染 - 孩子被卸载并且他们的状态被重新初始化。因此,例如,当它们不应该清除时,我的对话框中的字段会被清除。
这已经是一个相当复杂的应用程序,所以我今天花了很多时间来隔离问题。然后我设置了一个简单的 create-react-app 来尝试在那里复制这种行为 - 但这个测试应用程序的行为就像它应该的那样。更改父状态,无论是通过 prop 回调,还是通过来自子级的上下文提供的回调 - 重新渲染但不卸载/重新安装并且子状态保持不变。
但是在我的真实应用程序中,组件重新安装并且子状态重新初始化。
我已经将它简化到我所能做到的最低限度——我正在通过孩子的上下文设置一个带有“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>
);
};
Run Code Online (Sandbox Code Playgroud)
在 Menu.jsx 中:
const Menu = props => {
const appControl = useContext(AppContext);
// ...
return (
... super simplified for test
<div onClick={appControl.toggleFoo}>
Toggle Foo
</div>
);
};
Run Code Online (Sandbox Code Playgroud)
如果我正确理解状态,我确实相信改变状态应该导致儿童被重新渲染,而不是重新安装。这是我在简单的 create-react-app 测试中看到的,但不是在我的真实应用中。
我确实看到我没有使用最新的 React - 也许升级会解决这个问题?
感谢您对我可能做错了什么或在这里误解的任何见解。
Eri*_*c S 19
解决了。这是一个有趣的。这就是发生的事情。
在我的 App 组件中,我有一个相当深的 HOC 树。由于我的一些可疑决定,我最终将 App 分成了两个组件。应用程序和 AppCore。我有理由这样做,而且在凌晨 3 点似乎是有道理的。但是为了既快速又肮脏,我将 AppCore 作为常量,在我的 App 函数中。我记得自己在想“我想知道这会导致什么问题?” 现在我知道了。不过,也许 React 专家可以向我充分解释这一点,因为我没有看到分配给常量的 JSX 和直接返回 JSX 之间的区别。但显然有,而且很容易重现。
要重现, create-react-app 一个测试应用程序:
create-react-app test
cd test
Run Code Online (Sandbox Code Playgroud)
然后将 App.js 的内容替换为:
import React, { useState, useEffect } from "react";
const Menu = props => <div onClick={props.click}>Toggle Foo</div>;
const Test = props => {
useEffect(() => {
console.log("mounted");
return () => console.log("unmounted");
}, []);
return null;
};
const App = props => {
const [foo, setFoo] = useState(false);
// this is the root of the problem
// move this line outside of the function body
// and it mounts/unmounts correctly
const AppCore = props => <Test />;
return (
<>
<Menu click={() => setFoo(!foo)} />
<AppCore />
</>
);
};
export default App;
Run Code Online (Sandbox Code Playgroud)
然后 npm start,当您单击“Toggle Foo”时,您将看到 Test 组件已卸载/重新安装。
这里的解决方案是简单地将 AppCore 移出函数体。在我的真实应用中,这意味着我需要进行一些重构。
我想知道这是否会被视为 React 问题?
| 归档时间: |
|
| 查看次数: |
4120 次 |
| 最近记录: |