React JS:非父子关系的两个独立文件如何传递pikerdate变量
解决方案
因为两个组件没有父子层级,无法直接通过props传值,有三种常用实现方式:
方案1:使用React内置Context API(无需额外依赖)
React原生支持的跨组件传值方案,适合中小项目:
- 新建
src/context/DateContext.js文件,代码如下:
import { createContext, useContext, useState } from 'react'; import moment from 'moment'; const DateContext = createContext(); export function DateProvider({ children }) { const [selectedDate, setSelectedDate] = useState(moment(new Date()).format("YYYY-MM-DD")); return ( <DateContext.Provider value={{ selectedDate, setSelectedDate }}> {children} </DateContext.Provider> ) } export const useDate = () => useContext(DateContext);
- 在根组件(一般是App.js)中用Provider包裹所有需要用到这个日期的组件:
import { DateProvider } from './context/DateContext'; function App() { return ( <DateProvider> {/* 原有项目所有组件,包括Calendar和Diet组件都放在此处 */} </DateProvider> ) }
- 修改
calendar.js代码,选中日期时更新Context的值:
import moment from "moment"; import TrackerByDate from "./traker_by_date/tabs"; import { useDate } from '../context/DateContext'; // 引入自定义hook export default function Calender() { const [value] = useState(new Date()); const [show, setTracker] = useState(false); const { setSelectedDate } = useDate(); // 取全局日期更新方法 const [dateState, setDateState] = useState(new Date()); const changeDate = (e) => { setDateState(e); }; var pikerdate = moment(dateState).format("YYYY-MM-DD"); function clickTracker(e) { setSelectedDate(pikerdate); // 点击日期时更新全局日期值 setTracker(!show); } return ( <> {show ? <TrackerByDate dataFromParent={pikerdate} /> : null} <div style={{ width: "260px" }} className="res-calendar"> <Calendar className={["c1", "c2"]} onChange={changeDate} onClickDay={clickTracker} value={dateState} /> </div> </> ); }
- 在
diet.js中直接获取选中的日期:
import { useDate } from '../context/DateContext'; export default function Diet() { const { selectedDate } = useDate(); // 直接拿到最新选中的日期 // 后续业务逻辑可直接使用该变量 }
方案2:使用轻量状态管理库Zustand(代码更简洁)
如果项目允许引入第三方依赖,Zustand比Context更简单,不需要嵌套Provider:
- 先安装依赖:
npm install zustand - 新建
src/store/useDateStore.js:
import { create } from 'zustand'; import moment from 'moment'; const useDateStore = create((set) => ({ selectedDate: moment(new Date()).format("YYYY-MM-DD"), setSelectedDate: (date) => set({ selectedDate: date }), })); export default useDateStore;
- 修改
calendar.js:
// 其他引入不变 import useDateStore from '../store/useDateStore'; export default function Calender() { // 其他state不变 const setSelectedDate = useDateStore(state => state.setSelectedDate); var pikerdate = moment(dateState).format("YYYY-MM-DD"); function clickTracker(e) { setSelectedDate(pikerdate); // 点击时更新全局日期 setTracker(!show); } // 其余return部分保持不变 }
- 在
diet.js中取值:
import useDateStore from '../store/useDateStore'; export default function Diet() { const selectedDate = useDateStore(state => state.selectedDate); // 直接使用即可 }
方案3:自定义事件总线(适合临时快速实现)
如果不想修改全局结构,可以用事件发布订阅的方式实现,要注意组件销毁时取消监听避免内存泄漏:
- 新建
src/utils/eventBus.js:
class EventBus { constructor() { this.events = {}; } on(eventName, callback) { if (!this.events[eventName]) this.events[eventName] = []; this.events[eventName].push(callback); } emit(eventName, data) { if (this.events[eventName]) { this.events[eventName].forEach(cb => cb(data)); } } off(eventName, callback) { if (this.events[eventName]) { this.events[eventName] = this.events[eventName].filter(cb => cb !== callback); } } } export default new EventBus();
- 修改
calendar.js点击时发布事件:
// 其他引入不变 import eventBus from '../utils/eventBus'; function clickTracker(e) { eventBus.emit('dateChange', pikerdate); // 发布日期变更事件 setTracker(!show); }
- 在
diet.js中监听事件:
import { useEffect } from 'react'; import eventBus from '../utils/eventBus'; export default function Diet() { useEffect(() => { const handleDateChange = (date) => { // 拿到最新的日期date,执行你的业务逻辑 console.log('选中的日期:', date); } eventBus.on('dateChange', handleDateChange); // 组件销毁时取消监听 return () => eventBus.off('dateChange', handleDateChange); }, []) }
内容的提问来源于stack exchange,提问作者vivek kn
相关产品推荐
相关产品推荐

