I am trying to separate some logic from my component into a custom hook. I feel like i’m misunderstanding some fundamentals but I thought my code would work.
Custom hook:
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
}
const useEvent = () => {
const [events, dispatchEvent] = useReducer(
eventsReducer,
[],
initEvents
)
useEffect(() => {
const saveEventsToStorage = () => {
localStorage.setItem('savedEvents', JSON.stringify(events))
}
saveEventsToStorage()
}, [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])
return {
events,
getEventByDate,
dispatchEvent,
}
}
export default useEvent
Here Hour component:
const Hour = ({ dayWithHour }) => {
const { getEventByDate } = useEvent()
const hasEvent = !!getEventByDate(dayWithHour).length
return (
<Container hasEvent={hasEvent}></Container>
)
}
And function for adding new event in another component:
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)
})
}
I have hook thats store events(useEvent) and i need to update component Hour, when I add new event.
>Solution :
This is a case that I have suffered before. I totally see you. In React, hooks are not meant to share state across different components unless they are enclosed in a Context. When you call useEvent() in different components, you are not accessing the same hook instance but rather creating a new one each time. As a result, your Hour component and your other component that adds a new event are not sharing the same state of events, and that’s why Hour is not updating when a new event is added.
To solve this issue, you should consider using the Context API, which allows you to share state across different components. And in your root component, wrap the components that need to access the events state with EventsProvider. Here you can find more info about Context: https://react.dev/reference/react/useContext
Another solution is to call the useEvent in the parent component and then send getEventByDate and dispatchEvent as prop to the children. Be careful about calling the useEvent custom hook just once.