0

I have a very simple hook that works as intended:

const subscriptions: Subscription[] = []

const useEvents = () => {
  const subscribe = (type: Type, callback: () => void) => {
    const id = nanoid(8)
    subscriptions.push({
      id,
      type,
      callback,
    })
    return () => {
      subscriptions.splice(
        subscriptions.findIndex((s) => s.id === id),
        1
      )
    }
  }

  const dispatch = (type: Type) => {
    for (const subscription of subscriptions.filter((s) => s.type === type)) {
      subscription.callback()
    }
  }
  return { subscribe, dispatch }
}

I subscribe so:

useEffect(() => {
  subscribe("run", () => {
    console.log("RUN!!")
  })
}, [])

The problem is that when the app is hot-reloading subscribe is called again and the callback duplicated, is there any way to avoid this?

Daniel A. White
  • 187,200
  • 47
  • 362
  • 445
Trufa
  • 39,971
  • 43
  • 126
  • 190
  • Is React.Strict mode is on? According to this: https://stackoverflow.com/questions/60618844/react-hooks-useeffect-is-called-twice-even-if-an-empty-array-is-used-as-an-ar StrictMode renders components twice (on dev but not production) in order to detect any problems with your code and warn you about them – Kevin Z Jun 01 '22 at 16:23
  • @KevinZ I am aware this will only happen in dev and only when I edit this particular component. – Trufa Jun 01 '22 at 16:26
  • @Trrufa Sorry about that, could you clarify your question. Which library is handling your hot reload? Because if it's just next.js hot reload there's no way to avoid calling useEffect again. https://nextjs.org/docs/basic-features/fast-refresh but if you're using react-hot-loader, you can config it to ignore hooks. https://www.npmjs.com/package/react-hot-loader – Kevin Z Jun 01 '22 at 16:33
  • @KevinZ yes, it is fast-refresh from next.js unfortunately. – Trufa Jun 01 '22 at 16:37
  • I did some more research and I think if you pass in an argument to the array like a Boolean you can stop it from calling subscribe twice. It will still run your hook however you can stop it from updating based on the Boolean value. If bool false return else run subscribe and then set the bool to false. – Kevin Z Jun 01 '22 at 16:59
  • @KevinZ interesting, thanks, but I don't get what boolean should I pass it? – Trufa Jun 01 '22 at 17:23
  • Isn't that telling you that you're missing an unsubscribe action? The `subscribe` function returns another function that removes the event from the `subscriptions` array. You should be calling that function in the `useEffect`'s cleanup phase. For instance, you'd first have `const unsubscribe = subscribe("run", () => { console.log("RUN!!") })`, then in `useEffect` cleanup phase you'd have `() => { unsubscribe() }`. – juliomalves Jun 03 '22 at 12:14

0 Answers0