我如何在不卸载的情况下渲染组件数组?

卡尔·泰勒

我有一组React组件,它们从map函数接收道具,但是问题是这些组件在任何状态更新时都可以安装和卸载。这不是数组键的问题。请参阅codesandbox链接。

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类似的外部渲染它们,则如下所示,该组件会在任何状态更改时保持不变。

<Comp1 isActive={x === y}
<Comp2 isActive={x === y}

很想知道我在这里困惑时做错了什么。

请看看这个Codesandbox

我相信在声明返回组件的函数数组时我做错了,如您所见,按下按钮时ComponentOne被重新渲染,而第二个组件则没有。

TJ人群

我认为有两个问题:

  1. 为了让React有效地重用它们,您需要向它们添加一个key属性

    return (
        <div>
            {components.map((Comp, index) => {
                const isActive = index === currentIndex;
                return <Comp key={anAppropriateKeyValue} isActive={isActive} />;
            })}
       </div>
    );
    

    除非列表的顺序永不改变indexkey否则不要仅仅使用for (但是列表是静态的就可以了,因为它似乎在您的问题中)。这可能意味着您需要将数组更改为具有键和组件的对象数组。上面链接的文档中

    如果项目的顺序可能改变,我们不建议对索引使用索引。这会对性能产生负面影响,并可能导致组件状态出现问题。查阅Robin Pokorny的文章,深入了解使用索引作为键的负面影响如果您选择不为列表项分配显式键,那么React将默认使用索引作为键。

  2. 我怀疑您example每次都在重新创建阵列。这意味着您每次在数组初始化器中创建的函数都会被重新创建,这意味着对React来说,它们与先前的渲染功能不同。而是使这些功能稳定。有两种方法可以做到这一点,但是例如,您可以直接回调中使用LandingFirstStepCameraOnboarding组件map

    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>

本文收集自互联网,转载请注明来源。

如有侵权,请联系 [email protected] 删除。

编辑于
0

我来说两句

0 条评论
登录 后参与评论

相关文章

如何在不重新渲染随机放置的同级组件数组的情况下基于滚动位置更新样式化组件的样式?

我如何在不卸载Xcode的情况下删除iOS模拟器

如何在不更改状态的情况下重新渲染组件

如何在不渲染子组件的情况下根据子组件的大小更改React父组件的大小?

我如何在不创建组件的情况下在Vue.js中渲染createElement()的结果

我如何在不渲染的情况下从ERB代码块中获得收益?

如何在不渲染的情况下清除堆积图

如何在不继承的情况下访问组件的属性

我如何在不初始化常量的情况下声明数组?

我如何在不匹配的情况下随机播放两个js数组

如何在不排序的情况下从对象输出数组

如何在不爆炸的情况下映射 Spark 数组?

如何在不更新先前渲染的情况下渲染 onClick 事件的不同数据?

您如何在不卸载的情况下“禁用” oh-my-zsh(和zsh)?

如何在不卸载音频驱动程序的情况下打开音量系统图标?

如何在不卸载Ubuntu-Desktop的情况下从Ubuntu安装XFCE(Xubuntu)

如何在不卸载应用程序的情况下删除容器?

Angular 2-如何在不两次渲染子组件的情况下将数据传递给子组件?

如何在不实际渲染我的网页的情况下渲染 404?

如何在 ReactJS 中不重新渲染整个树的情况下渲染树组件的叶子组件

如何在不指定组件类型的情况下将父组件注入共享指令?

如何在不更改组件状态的情况下更改组件状态的副本?

我如何在没有软件中心或终端的情况下卸载Steam

如何在不重新渲染组件的情况下更新反应状态?

如何在React Native中不使用任何API调用的情况下重新渲染组件?

如何在不重新渲染父组件的情况下正确获取鼠标事件

在 .Net 核心中。如何在不产生错误的情况下渲染部分

如何在不添加标签的情况下渲染innerHTML

如何在不渲染树枝模板的情况下进行分析?