[英]How to store components in an array and render them when I need in React?
[英]How can I render an array of components in react without them unmounting?
我有一組 React 組件,它們從 map function 接收道具,但是問題是組件在任何 state 更新上都已安裝和卸載。 這不是數組鍵的問題。 請參閱代碼和框鏈接。
const example = () => {
const components = [
(props: any) => (
<LandingFirstStep
eventImage={eventImage}
safeAreaPadding={safeAreaPadding}
isActive={props.isActive}
onClick={progressToNextIndex}
/>
),
(props: any) => (
<CameraOnboarding
safeAreaPadding={safeAreaPadding}
circleSize={circleSize}
isActive={props.isActive}
onNextClick={progressToNextIndex}
/>
),
];
return (
<div>
{components.map((Comp, index) => {
const isActive = index === currentIndex;
return <Comp key={`component-key-${index}`} isActive={isActive} />;
})}
</div>
)
}
如果我將它們呈現在component.map
之外,如下所示,該組件會在任何 state 更改時持續存在。
<Comp1 isActive={x === y}
<Comp2 isActive={x === y}
很想知道我在這里做錯了什么,因為我很困惑。
請看一下這個Codesandbox 。
我相信在聲明返回組件的函數數組時我做錯了,如您所見,按下按鈕時會重新呈現 ComponentOne,但不會重新呈現組件 2。
你應該看看 React 中的key屬性。 它幫助 React 識別哪些項目已更改、添加或刪除。 應為數組內的元素提供鍵,以使元素具有穩定的身份
我認為有兩個問題:
為了讓 React 有效地重用它們,你需要給它們添加一個key
屬性:
return ( <div> {components.map((Comp, index) => { const isActive = index === currentIndex; return <Comp key={anAppropriateKeyValue} isActive={isActive} />; })} </div> );
不要只使用index
作為key
,除非列表的順序永遠不會改變(但如果列表是 static 也可以,因為它似乎在您的問題中)。 這可能意味着您需要將數組更改為包含鍵和組件的對象數組。 從上面鏈接的文檔:
如果項目的順序可能發生變化,我們不建議對鍵使用索引。 這會對性能產生負面影響,並可能導致組件 state 出現問題。 查看 Robin Pokorny 的文章, 深入解釋使用索引作為鍵的負面影響。 如果您選擇不為列表項分配顯式鍵,那么 React 將默認使用索引作為鍵。
我懷疑您每次都在重新創建example
數組。 這意味着您在數組初始化程序中創建的函數每次都會重新創建,這意味着對於 React,它們與之前的渲染不是同一個組件 function。 相反,使這些功能穩定。 有幾種方法可以做到這一點,但例如,您可以直接在map
回調中使用您的LandingFirstStep
和CameraOnboarding
組件。
const components = [ { Comp: LandingFirstStep, props: { // Any props for this component other than `isActive`... onClick: progressToNextIndex } }, { Comp: CameraOnboarding, props: { // Any props for this component other than `isActive`... onNextClick: progressToNextIndex } }, ];
然后在map
中:
{components.map(({Comp, props}, index) => { const isActive = index === currentIndex; return <Comp key={index} isActive={isActive} {...props} />; })}
還有其他方法來處理它,例如通過useMemo
或useCallback
,但對我來說這是一種簡單的方法——如果你需要一個有意義的鍵而不是使用index
,它可以讓你放置一個有意義的鍵。
這是一個處理這些事情並顯示組件何時安裝/卸載的示例; 如您所見,當索引更改時,它們不再卸載/掛載:
const {useState, useEffect, useCallback} = React; function LandingFirstStep({isActive, onClick}) { useEffect(() => { console.log(`LandingFirstStep mounted`); return () => { console.log(`LandingFirstStep unmounted`); }; }, []); return <div className={isActive? "active": ""} onClick={isActive && onClick}>LoadingFirstStep, isActive = {String(isActive)}</div>; } function CameraOnboarding({isActive, onNextClick}) { useEffect(() => { console.log(`CameraOnboarding mounted`); return () => { console.log(`CameraOnboarding unmounted`); }; }, []); return <div className={isActive? "active": ""} onClick={isActive && onNextClick}>CameraOnboarding, isActive = {String(isActive)}</div>; } const Example = () => { const [currentIndex, setCurrentIndex] = useState(0); const progressToNextIndex = useCallback(() => { setCurrentIndex(i => (i + 1) % components.length); }); const components = [ { Comp: LandingFirstStep, props: { onClick: progressToNextIndex } }, { Comp: CameraOnboarding, props: { onNextClick: progressToNextIndex } }, ]; return ( <div> {components.map(({Comp, props}, index) => { const isActive = index === currentIndex; return <Comp key={index} isActive={isActive} {...props} />; })} </div> ); }; ReactDOM.render(<Example/>, document.getElementById("root"));
.active { cursor: pointer; }
<div id="root"></div> <script src="https://cdnjs.cloudflare.com/ajax/libs/react/17.0.1/umd/react.production.min.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/17.0.1/umd/react-dom.production.min.js"></script>
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.