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

ReactJS便捷传递数据至子组件的辅助组件需求及示例

这场景太熟悉了——不想一层一层手动传递props,希望子组件能自动获取上层指定的数据对吧?咱们可以利用React的Context API来实现这个<Block>辅助组件,完美解决props drilling的痛点,让数据传递更简洁。

实现思路

核心思路是通过嵌套的Context Provider来维护当前层级的数据上下文:

  • 当<Block>接收data属性时,它会作为当前层级的基础数据
  • 当<Block>接收name属性时,它会从父级上下文中取出对应字段的值,作为当前层级的上下文数据
  • 子组件可以通过自定义Hook直接获取当前上下文里对应name的字段值

1. 创建数据上下文和工具Hook

首先我们需要创建一个React Context,以及一个自定义Hook来方便子组件消费数据:

import { createContext, useContext, useMemo } from 'react';

// 创建数据上下文,初始值为空对象
const DataContext = createContext({});

// 自定义Hook:获取当前上下文的数据,并根据name取出对应值
export const useData = (name) => {
  const contextData = useContext(DataContext);
  return name ? contextData[name] : contextData;
};

2. 实现<Block>组件

<Block>组件的核心是合并父级上下文和自身的data/name属性,然后提供新的Context:

export const Block = ({ data, name, children }) => {
  // 获取父级上下文的数据
  const parentData = useContext(DataContext);
  
  // 计算当前层级要提供的数据
  const currentData = useMemo(() => {
    if (data) {
      // 如果传入了data,直接用这个作为当前上下文(若需和父级合并,可改为{...parentData, ...data})
      return data;
    }
    if (name) {
      // 如果传入了name,从父级上下文取出对应字段作为当前上下文
      return parentData[name] || {};
    }
    // 什么都没传则继承父级上下文
    return parentData;
  }, [parentData, data, name]);

  return (
    <DataContext.Provider value={currentData}>
      {children}
    </DataContext.Provider>
  );
};

注:如果需要支持父级data和传入的data合并,可把return data改成return {...parentData, ...data},根据业务需求调整即可。

3. 实现消费数据的子组件(比如TextBox)

现在子组件可以通过useDataHook轻松获取对应的数据,比如示例中的<TextBox>:

export const TextBox = ({ name }) => {
  const value = useData(name);
  return <input type="text" value={value || ''} readOnly />;
};

完整示例代码

把所有部分整合起来,就是你给出的使用场景的完整实现:

import { createContext, useContext, useMemo } from 'react';

const DataContext = createContext({});

export const useData = (name) => {
  const contextData = useContext(DataContext);
  return name ? contextData[name] : contextData;
};

export const Block = ({ data, name, children }) => {
  const parentData = useContext(DataContext);
  
  const currentData = useMemo(() => {
    if (data) {
      return data;
    }
    if (name) {
      return parentData[name] || {};
    }
    return parentData;
  }, [parentData, data, name]);

  return (
    <DataContext.Provider value={currentData}>
      {children}
    </DataContext.Provider>
  );
};

export const TextBox = ({ name }) => {
  const value = useData(name);
  return <input type="text" value={value || ''} readOnly />;
};

// 你的Test组件
const Test = () => { 
  const data = { 
    loginForm: { name: "Batman", password: "hard password" }, 
    email: "test@gmail.com" 
  }; 
  return ( 
    <Block data={data}> 
      <div> 
        <TextBox name="email" /> 
      </div> 
      <form> 
        <Block name="loginForm"> 
          <div> 
            <TextBox name="name" /> 
          </div> 
          <div> 
            <TextBox name="password" /> 
          </div> 
        </Block> 
      </form>
    </Block>
  )
};

扩展优化建议

  • 添加类型支持:如果用TypeScript,可以给Context、组件、Hook加上泛型,让类型更安全
  • 处理空值:在useData里可以添加默认值参数,比如useData(name, defaultValue),避免渲染空输入框
  • 支持数据更新:如果需要子组件修改数据,可以在Context里加入setter函数,实现双向绑定
  • 性能优化:可以用memo包裹<Block>和子组件,避免不必要的重渲染

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.25 03:27:53