React组件间传递onClick事件获取值的实现方案
React组件间数据传递与员工筛选实现方案
嘿,这个需求在React开发里挺常见的,我帮你梳理下具体实现步骤,分场景给你讲清楚:
一、核心思路
不管组件关系如何,核心就是两步:
- 把报表组件中选中的月份数据传递到员工组件
- 在员工组件(或共同父组件)中,用这个月份去筛选符合条件的在职员工
二、分场景实现
场景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:组件无直接层级(兄弟/跨层级)
如果两个组件不在同一个父组件下,或者层级很深,推荐两种方案:
- 状态提升:把选中月份的状态提到它们共同的祖先组件里,和上面的思路类似,只是祖先组件层级更高
- 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.
相关产品推荐
相关产品推荐

