簡體   English   中英

如何在不卸載它們的情況下渲染一組組件?

[英]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 識別哪些項目已更改、添加或刪除。 應為數組內的元素提供鍵,以使元素具有穩定的身份

我認為有兩個問題:

  1. 為了讓 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 將默認使用索引作為鍵。

  2. 我懷疑您每次都在重新創建example數組。 這意味着您在數組初始化程序中創建的函數每次都會重新創建,這意味着對於 React,它們與之前的渲染不是同一個組件 function。 相反,使這些功能穩定。 有幾種方法可以做到這一點,但例如,您可以直接在map回調中使用您的LandingFirstStepCameraOnboarding組件。

     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} />; })}

    還有其他方法來處理它,例如通過useMemouseCallback ,但對我來說這是一種簡單的方法——如果你需要一個有意義的鍵而不是使用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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM