如何强制 React(使用钩子的功能组件)在道具更改时从头开始创建新组件?



TLDR

有没有办法强制 React 从头开始重新创建一个组件(使用钩子的功能组件),而不是在prop更改时重新渲染它?

编辑

键属性确实有效。我遇到的问题是由于我正在执行的状态更新序列。第一次更新是立即尝试渲染需要完成最后一次更新的组件。


我正在开发一个名为<AddProductWidget>的组件,它将获得有关产品的以下props,并需要显示其详细信息。它属于带有搜索栏的页面,您可以填写产品ID,并从云函数获取产品详细信息。

它的呈现方式如下:

<AddProductWidget
userImages={props.productDetails.userImages}    // Array of strings (urls)
title={props.productDetails.title}
stars={props.productDetails.stars}
/>

添加产品小部件.js

它呈现一个<UserImages>组件,允许用户在保存到数据库之前单击一些图像进行选择。因此,它需要一个state来"记住"用户点击了哪些图像。

function AddProductWidget(props) {
const [userImagesSelected, setUserImagesSelected] = useState(
() => {
if (props.userImages && props.userImages > 0) {
return new Array(props.userImages.length).fill(false);
}
return null;
}
);
// IT renders the <UserImages> component
// The code here is simplified
return(
<UserImages
userImages={props.userImages}
userImagesSelected={userImagesSelected}
setUserImagesSelected={setUserImagesSelected}
/>
);
}

该数组userImagesSelected的初始状态应与userImages数组的长度相同,并填充false值,一旦用户开始单击图像,这些值将变得true。如果产品没有用户图像,则将props.userImagesnulluserImagesSelected也应null

当我加载第一个产品时,一切都按预期工作。无论它是否有图像,一切都被正确显示。

问题:

问题是,例如,当我加载一个带有零图像的产品,然后我加载另一个具有 5 个图像的产品时。基本上AddProductWidgetprops会改变(因为它收到了新产品),但由于 React 似乎正在尝试使用相同的组件实例,所以我得到一个错误,因为我的UserImages组件会尝试渲染选定的图像信息,但userImagesSelected的状态仍然会null, 因为最后的产品没有图像。

当我使用类时,我可以强制 React 使用key属性重新创建一个组件实例,但这似乎不适用于钩子,因为以下代码没有解决我的问题:

<AddProductWidget
key={productID}
userImages={props.productDetails.userImages}    // Array of strings (urls)
title={props.productDetails.title}
stars={props.productDetails.stars}
/>

问题

有没有办法强制 React 从头开始重新创建一个组件(使用钩子的功能组件),而不是在prop更改时重新渲染它?

额外

A 找到了解决方法,但它似乎有点笨拙,即使它在 React 文档中。它基本上使用状态来检测props何时更改并在渲染期间调用setState()。我希望从头开始重新创建我的组件更好。

Hooks FAQ:如何实现 getDerivedStateFromProps

不确定您如何决定不同的key不会重新挂载组件,但它应该这样做(您确定密钥已更改吗?

这是一个运行示例,显示了这一点

function Test() {
React.useEffect(() => {
console.log('Test was mounted');
return () => {
console.log('Test was un-mounted');
};
}, []);
return "hi there, I'm Test";
}
function App() {
const [val, setVal] = React.useState("Change me...");
return (
<div className="App">
<input value={val} onChange={e => setVal(e.target.value)} />
<br />
<Test key={val} />
</div>
);
}
const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);
<script crossorigin src="https://unpkg.com/react@16/umd/react.development.js"></script>
<script crossorigin src="https://unpkg.com/react-dom@16/umd/react-dom.development.js"></script>
<div id="root" />

相关内容

  • 没有找到相关文章

最新更新