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

自定义Hook管理事件状态后,Hour组件无法同步更新的问题求助

自定义Hook管理事件状态后,Hour组件无法同步更新的问题求助

嘿,我仔细看了你的代码,马上就发现问题所在了——每个组件调用useEvent()的时候,都会创建一套完全独立的状态实例!这就导致你在添加事件的组件里更新的事件列表,和Hour组件里读取的事件列表根本不是同一个东西,Hour组件自然不会感知到变化并更新啦😯

问题核心:自定义Hook的特性

自定义Hook的作用是复用逻辑,但它本质上是把组件里的state、effect等逻辑抽出来,每次调用Hook都会重新初始化这些状态。所以你的Hour组件和添加事件的组件各自调用useEvent(),相当于各自维护了一份独立的events数组、dispatchEvent方法,甚至连localStorage的读写都是各自独立的,两者之间完全没有关联。

解决办法:用Context共享状态

既然需要多个组件共享同一套事件状态,我们可以把useEvent里的状态逻辑放到React Context中,让所有需要的组件从Context里获取状态和方法,这样大家用的都是同一个状态实例,更新时自然能同步。

第一步:创建EventContext和Provider

把原来useEvent里的逻辑搬到Context Provider中,这样所有子组件都能共享这个状态:

import { createContext, useContext, useReducer, useEffect, useCallback } from 'react';
import { format } from 'date-fns'; // 假设你用的是date-fns的format方法

// 保留你原来的reducer和初始化函数
function eventsReducer(events, action) {
  switch (action.type) {
    case 'add': {
      return [
        ...events,
        { date: action.date }
      ];
    }
    case 'delete': {
      return events.filter((t) => t.date !== action.date);
    }
    default:
      throw new Error('No such action');
  }
}

const initEvents = () => {
  const eventsFromStorage = localStorage.getItem('savedEvents');
  const parsedEvents = eventsFromStorage ? JSON.parse(eventsFromStorage) : [];
  return parsedEvents;
};

// 创建Context
const EventContext = createContext();

// 定义Provider组件,包裹需要共享状态的子组件
export const EventProvider = ({ children }) => {
  const [events, dispatchEvent] = useReducer(eventsReducer, [], initEvents);

  useEffect(() => {
    localStorage.setItem('savedEvents', JSON.stringify(events));
  }, [events]);

  const getEventByDate = useCallback((date) => {
    return events.filter(
      event => format(new Date(event.date), 'yyyy MM d H') === format(new Date(date), 'yyyy MM d H')
    );
  }, [events]);

  // 把需要共享的状态和方法放到Context value里
  const contextValue = {
    events,
    getEventByDate,
    dispatchEvent,
  };

  return (
    <EventContext.Provider value={contextValue}>
      {children}
    </EventContext.Provider>
  );
};

// 重新定义useEvent Hook,用来获取Context
export const useEvent = () => {
  const context = useContext(EventContext);
  if (!context) {
    throw new Error('useEvent必须在EventProvider内部使用哦');
  }
  return context;
};

第二步:在父组件中包裹EventProvider

找到你的根组件(比如App.js),用EventProvider包裹所有需要使用事件状态的组件:

import { EventProvider } from './EventContext';

function App() {
  return (
    <EventProvider>
      {/* 这里放你的Hour组件、添加事件的组件,以及其他需要用到事件状态的组件 */}
    </EventProvider>
  );
}

第三步:原组件代码无需改动

你的Hour组件和添加事件的组件依然可以像之前一样调用useEvent(),但现在它们获取的是Context中共享的状态:

// Hour组件
const Hour = ({ dayWithHour }) => {
  const { getEventByDate } = useEvent();
  const hasEvent = !!getEventByDate(dayWithHour).length;
  return <Container hasEvent={hasEvent}></Container>;
};

// 添加事件的组件
const AddEventButton = () => {
  const { dispatchEvent } = useEvent();
  const handleClick = () => {
    const promptData = prompt('Enter event time: YYYY-MM-DD HH:mm:ss');
    if (!promptData) return;
    dispatchEvent({
      type: 'add',
      date: new Date(promptData)
    });
  };
  return <button onClick={handleClick}>添加事件</button>;
};

这样修改之后,当你添加新事件时,Context里的events会更新,所有使用useEvent()的组件都会感知到变化,Hour组件里的hasEvent也会随之更新,从而触发组件重新渲染啦!

备注:内容来源于stack exchange,提问作者MaybeRainQ

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.22 09:29:30