You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

React中如何向嵌套SkeletonTile子组件自动注入递增delay属性

可行实现方案

方案1:递归克隆子元素(无需修改现有SkeletonTile组件)

你之前修改props失败是因为直接修改了React元素的只读属性,使用React.cloneElement生成新的元素实例即可解决,该方法会自动合并原有props和新增props,不会丢失你自定义的width、height等属性。

import React, { Children, cloneElement, isValidElement } from 'react';
import SkeletonTile from './SkeletonTile';

type ControllerProps = {
  delayIncrease: number;
  children: React.ReactNode;
};

const SkeletonController: React.FC<ControllerProps> = ({ delayIncrease, children }) => {
  // 维护delay计数器
  let delayCount = 0;

  // 递归遍历子节点的函数
  const processChildren = (nodes: React.ReactNode): React.ReactNode => {
    return Children.map(nodes, node => {
      // 非合法React元素直接返回
      if (!isValidElement(node)) return node;

      // 匹配到SkeletonTile组件则注入delay
      if (node.type === SkeletonTile) {
        const currentDelay = delayCount * delayIncrease;
        delayCount++;
        // 优先使用用户手动传入的delay属性
        return cloneElement(node, { delay: node.props.delay ?? currentDelay });
      }

      // 其他元素递归处理子节点
      if (node.props.children) {
        return cloneElement(node, {
          ...node.props,
          children: processChildren(node.props.children)
        });
      }

      return node;
    });
  };

  return <>{processChildren(children)}</>;
};

该方案优缺点:

  • 优点:无需修改现有SkeletonTile组件,侵入性极低
  • 缺点:嵌套层级极深时会有微小性能损耗,如果SkeletonTile被高阶组件包裹,需要通过静态displayName属性做类型判断(比如判断node.type.displayName === 'SkeletonTile')

方案2:基于Context实现(性能更优,适配任意嵌套场景)

如果SkeletonTile可能嵌套在自定义组件内部,推荐用Context方案,不需要遍历克隆整个节点树,性能更优。

首先定义共享Context:

import { createContext, useContext } from 'react';

const SkeletonContext = createContext({
  delayIncrease: 0.1,
  getNextDelay: () => 0,
});

修改SkeletonTile组件,新增Context消费逻辑:

type Props = {
  delay?: number;
  width?: string;
  height?: string;
};

const SkeletonTile: React.FC<Props> = ({ delay: customDelay, width, height }) => {
  const { getNextDelay } = useContext(SkeletonContext);
  // 优先使用用户手动传入的delay
  const delay = customDelay ?? getNextDelay();
  return <div style={{ animationDelay: `${delay}s`, width, height }} className="skeleton-tile"></div>;
};

实现SkeletonController:

type ControllerProps = {
  delayIncrease: number;
  children: React.ReactNode;
};

const SkeletonController: React.FC<ControllerProps> = ({ delayIncrease, children }) => {
  let count = 0;
  const getNextDelay = () => {
    const current = count * delayIncrease;
    count++;
    return current;
  };

  return (
    <SkeletonContext.Provider value={{ delayIncrease, getNextDelay }}>
      {children}
    </SkeletonContext.Provider>
  );
};

该方案优缺点:

  • 优点:性能更高,支持SkeletonTile嵌套在任意自定义组件内部使用,控制逻辑后续更易扩展
  • 缺点:需要对现有SkeletonTile做少量修改

内容的提问来源于stack exchange,提问作者zekro

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.24 12:06:05