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

React组件间传递onClick事件获取值的实现方案

React组件间数据传递与员工筛选实现方案

嘿,这个需求在React开发里挺常见的,我帮你梳理下具体实现步骤,分场景给你讲清楚:

一、核心思路

不管组件关系如何,核心就是两步:

  1. 把报表组件中选中的月份数据传递到员工组件
  2. 在员工组件(或共同父组件)中,用这个月份去筛选符合条件的在职员工

二、分场景实现

场景1:两个组件是父子关系

比如报表组件是父组件,员工列表是子组件,或者反过来:

  • 如果报表是父:在报表组件里维护选中月份的状态,把这个状态通过props传给员工子组件
  • 如果员工是父:把选中月份的状态放在父组件,通过props传给报表组件,报表点击时调用父组件的回调函数更新状态

举个代码例子(假设报表是父,员工是子):

// 父组件:ReportContainer.jsx
import { useState } from 'react';
import ReportComponent from './ReportComponent';
import EmployeeList from './EmployeeList';

// 模拟员工数据,每个员工有入职、离职日期
const mockEmployees = [
  { id: 1, name: '张三', hireDate: '2023-02-15', leaveDate: null }, // 仍在职
  { id: 2, name: '李四', hireDate: '2022-05-01', leaveDate: '2024-03-30' },
  { id: 3, name: '王五', hireDate: '2024-04-01', leaveDate: null },
];

export default function ReportContainer() {
  const [selectedMonth, setSelectedMonth] = useState(null); // 格式比如 '2024-05'

  // 报表组件点击时触发的回调
  const handleMonthClick = (month) => {
    setSelectedMonth(month);
  };

  // 筛选在职员工的逻辑
  const filterEmployees = () => {
    if (!selectedMonth) return [];
    
    // 把选中月份转成当月的第一天和最后一天
    const [year, month] = selectedMonth.split('-').map(Number);
    const monthStart = new Date(year, month - 1, 1);
    const monthEnd = new Date(year, month, 0); // 当月最后一天

    return mockEmployees.filter(emp => {
      const hireDate = new Date(emp.hireDate);
      const leaveDate = emp.leaveDate ? new Date(emp.leaveDate) : new Date(); // 离职为空则用当前日期

      // 判断:入职日期 <= 当月最后一天,且离职日期 >= 当月第一天
      return hireDate <= monthEnd && leaveDate >= monthStart;
    });
  };

  const filteredEmployees = filterEmployees();

  return (
    <div>
      <ReportComponent onMonthClick={handleMonthClick} />
      <EmployeeList employees={filteredEmployees} />
    </div>
  );
}

// 子组件:ReportComponent.jsx
export default function ReportComponent({ onMonthClick }) {
  // 模拟报表的月份列表
  const months = ['2024-03', '2024-04', '2024-05'];

  return (
    <div className="report">
      <h3>报表月份</h3>
      {months.map(month => (
        <button key={month} onClick={() => onMonthClick(month)}>
          {month}
        </button>
      ))}
    </div>
  );
}

// 子组件:EmployeeList.jsx
export default function EmployeeList({ employees }) {
  if (employees.length === 0) {
    return <p>暂无对应月份的在职员工</p>;
  }

  return (
    <div className="employee-list">
      <h3>当月在职员工</h3>
      <ul>
        {employees.map(emp => (
          <li key={emp.id}>{emp.name}</li>
        ))}
      </ul>
    </div>
  );
}

场景2:组件无直接层级(兄弟/跨层级)

如果两个组件不在同一个父组件下,或者层级很深,推荐两种方案:

  1. 状态提升:把选中月份的状态提到它们共同的祖先组件里,和上面的思路类似,只是祖先组件层级更高
  2. Context API:如果状态提升太麻烦,用React Context来全局共享选中月份的状态

举个Context的简单例子:

// 第一步:创建Context
import { createContext, useContext, useState } from 'react';

const MonthContext = createContext();

// 第二步:创建Provider组件
export function MonthProvider({ children }) {
  const [selectedMonth, setSelectedMonth] = useState(null);

  return (
    <MonthContext.Provider value={{ selectedMonth, setSelectedMonth }}>
      {children}
    </MonthContext.Provider>
  );
}

// 第三步:自定义Hook方便使用Context
export function useMonth() {
  return useContext(MonthContext);
}

// 然后在报表组件里用:
import { useMonth } from './MonthContext';

export default function ReportComponent() {
  const { setSelectedMonth } = useMonth();
  const months = ['2024-03', '2024-04', '2024-05'];

  return (
    <div className="report">
      <h3>报表月份</h3>
      {months.map(month => (
        <button key={month} onClick={() => setSelectedMonth(month)}>
          {month}
        </button>
      ))}
    </div>
  );
}

// 员工组件里用:
import { useMonth } from './MonthContext';
const mockEmployees = [/* 同之前的模拟数据 */];

export default function EmployeeList() {
  const { selectedMonth } = useMonth();

  // 筛选逻辑和之前一样
  const filterEmployees = () => {
    if (!selectedMonth) return [];
    const [year, month] = selectedMonth.split('-').map(Number);
    const monthStart = new Date(year, month - 1, 1);
    const monthEnd = new Date(year, month, 0);

    return mockEmployees.filter(emp => {
      const hireDate = new Date(emp.hireDate);
      const leaveDate = emp.leaveDate ? new Date(emp.leaveDate) : new Date();
      return hireDate <= monthEnd && leaveDate >= monthStart;
    });
  };

  const filteredEmployees = filterEmployees();

  return (
    <div className="employee-list">
      <h3>当月在职员工</h3>
      {filteredEmployees.length === 0 ? (
        <p>暂无对应月份的在职员工</p>
      ) : (
        <ul>
          {filteredEmployees.map(emp => (
            <li key={emp.id}>{emp.name}</li>
          ))}
        </ul>
      )}
    </div>
  );
}

// 最后在根组件包裹Provider:
import { MonthProvider } from './MonthContext';
import ReportComponent from './ReportComponent';
import EmployeeList from './EmployeeList';

function App() {
  return (
    <MonthProvider>
      <ReportComponent />
      <EmployeeList />
    </MonthProvider>
  );
}

三、关键细节提醒

  • 日期处理:尽量用Date对象来比较,不要直接用字符串(比如'2024-05'和'2024-05-15'字符串比较可能出问题),如果觉得原生Date麻烦,可以用dayjs或moment库简化处理
  • 筛选逻辑:根据你的实际员工数据结构调整,比如有的公司可能用“在职状态”字段,但大部分还是用入职/离职日期区间判断
  • 性能优化:如果员工数据量很大,可以用useMemo缓存筛选后的结果,避免每次渲染都重新计算:
    const filteredEmployees = useMemo(() => {
      // 这里放筛选逻辑
    }, [selectedMonth, mockEmployees]);
    

内容的提问来源于stack exchange,提问作者Dženis H.

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.21 08:08:32