子组件在react hooks中调用useState()时如何实现条件渲染?
How to implement conditional rendering while the children component calling useState() in react hooks?
最近我试图用 React Hooks 替换我项目中的 class 组件实现,但我在实现子组件的条件渲染时遇到了一些麻烦。
我有一个包含页眉、页脚和条件渲染子组件的父组件,该子组件根据父组件的状态渲染不同的子组件,并且其状态由另一个 useEffect 控制,如下面的代码所述。
但是,我的一个子组件包含一个简单的计数器,它由 useState() 实现,就像官方 React Hooks 教程中的示例一样。由于钩子规则规定我们只能在顶层调用钩子,所以我的应用程序在呈现此子项时崩溃了。
我想解决方案之一是将子组件的 useState() 放到父组件或使用类似 Redux 的实现?但这有点尴尬,因为计数器只是一个简单的逻辑,没有必要从组件中取出来。
所以我正在寻找另一种方法来解决这个问题。当然,如果我一开始的概念有误,请告诉我。
我的父组件:
const StorePage = (props) => {
const { children } = props;
const [detectedTagIds, setDetectedTagIds] = useState([]);
const [detectedProducts, setDetectedProducts] = useState([]);
const fetchProductByTagIds = (tagIds) => productController.getProducts({ tagId: tagIds })
.then(res => res.json())
.then(json => setDetectedProducts(json.result))
// monitor detected tags
useEffect(() => {
ws.addEventListener('message', (event) => {
const json = JSON.parse(event.data)
const { tagId } = json;
if (!_.includes(detectedTagIds, tagId)) {
setDetectedTagIds(_.concat(detectedTagIds, tagId));
}
});
}, []);
// fetch while detected tags are changed
useDeepCompareEffect(() => {
fetchProductByTagIds(detectedTagIds)
}, [detectedTagIds]);
return (
<div className="StorePage">
{Header({ detectedProducts })}
<div className="StorePage-content">
{
detectedTagIds.length === 0 ?
LandingPage() :
( detectedProducts.length === 1 ? ProductInfoPage({ detectedProduct: detectedProducts[0] }) : null )
}
</div>
{Footer({ detectedProducts })}
</div>
);
};
export default StorePage;
这是我得到的错误消息,我认为这是由 detectedProducts:
的变化触发的
Previous render Next render
------------------------------------------------------
1. useState useState
2. useState useState
3. useEffect useEffect
4. useRef useRef
5. useEffect useEffect
6. useState useState
7. useState useState
8. useState useState
9. useRef useState
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
有条件地渲染子组件是完全没问题的,即使这些子组件使用钩子,但你需要使用正常的反应方式来这样做:通过编写 jsx 标签,或者通过手动调用 React.createElement (这是 jsx 编译成的)。直接将子组件作为函数调用会导致您看到的问题。
return (
<div className="StorePage">
<Header detectedProducts={detectedProducts} />
<div className="StorePage-content">
{detectedTagIds.length === 0 ? (
<LandingPage/>
) : detectedProducts.length == 1 ? (
<ProductInfoPage detectedProducts={detectedProducts[0]} />
) : (
null
)}
</div>
<Footer detectedProducts={detectedProducts}/>
</div>
);
最近我试图用 React Hooks 替换我项目中的 class 组件实现,但我在实现子组件的条件渲染时遇到了一些麻烦。
我有一个包含页眉、页脚和条件渲染子组件的父组件,该子组件根据父组件的状态渲染不同的子组件,并且其状态由另一个 useEffect 控制,如下面的代码所述。
但是,我的一个子组件包含一个简单的计数器,它由 useState() 实现,就像官方 React Hooks 教程中的示例一样。由于钩子规则规定我们只能在顶层调用钩子,所以我的应用程序在呈现此子项时崩溃了。
我想解决方案之一是将子组件的 useState() 放到父组件或使用类似 Redux 的实现?但这有点尴尬,因为计数器只是一个简单的逻辑,没有必要从组件中取出来。
所以我正在寻找另一种方法来解决这个问题。当然,如果我一开始的概念有误,请告诉我。
我的父组件:
const StorePage = (props) => {
const { children } = props;
const [detectedTagIds, setDetectedTagIds] = useState([]);
const [detectedProducts, setDetectedProducts] = useState([]);
const fetchProductByTagIds = (tagIds) => productController.getProducts({ tagId: tagIds })
.then(res => res.json())
.then(json => setDetectedProducts(json.result))
// monitor detected tags
useEffect(() => {
ws.addEventListener('message', (event) => {
const json = JSON.parse(event.data)
const { tagId } = json;
if (!_.includes(detectedTagIds, tagId)) {
setDetectedTagIds(_.concat(detectedTagIds, tagId));
}
});
}, []);
// fetch while detected tags are changed
useDeepCompareEffect(() => {
fetchProductByTagIds(detectedTagIds)
}, [detectedTagIds]);
return (
<div className="StorePage">
{Header({ detectedProducts })}
<div className="StorePage-content">
{
detectedTagIds.length === 0 ?
LandingPage() :
( detectedProducts.length === 1 ? ProductInfoPage({ detectedProduct: detectedProducts[0] }) : null )
}
</div>
{Footer({ detectedProducts })}
</div>
);
};
export default StorePage;
这是我得到的错误消息,我认为这是由 detectedProducts:
的变化触发的 Previous render Next render
------------------------------------------------------
1. useState useState
2. useState useState
3. useEffect useEffect
4. useRef useRef
5. useEffect useEffect
6. useState useState
7. useState useState
8. useState useState
9. useRef useState
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
有条件地渲染子组件是完全没问题的,即使这些子组件使用钩子,但你需要使用正常的反应方式来这样做:通过编写 jsx 标签,或者通过手动调用 React.createElement (这是 jsx 编译成的)。直接将子组件作为函数调用会导致您看到的问题。
return (
<div className="StorePage">
<Header detectedProducts={detectedProducts} />
<div className="StorePage-content">
{detectedTagIds.length === 0 ? (
<LandingPage/>
) : detectedProducts.length == 1 ? (
<ProductInfoPage detectedProducts={detectedProducts[0]} />
) : (
null
)}
</div>
<Footer detectedProducts={detectedProducts}/>
</div>
);