search

Home  >  Q&A  >  body text

Why does every React component need to use useDispatch?

Yes, this question seems to be a duplicate of this question:

Should each component have a useDispatch?

But it is not repeated. I offer different methods:

Suppose I have 3 child components, and they all use the Redux Toolkit's dispatch function.

The usual way is this:

const ChildA = () => {
  const dispatch = useAppDispatch();

  const incr = useCallback(() => {
    dispatch(increment());
  }, [dispatch]);

  return <button onClick={incr}>ChildA</button>;
};

const ChildB = () => {
  const dispatch = useAppDispatch();

  const incr = useCallback(() => {
    dispatch(increment());
  }, [dispatch]);

  return <button onClick={incr}>ChildB</button>;
};

const ChildC = () => {
  const dispatch = useAppDispatch();

  const incr = useCallback(() => {
    dispatch(increment());
  }, [dispatch]);

  return <button onClick={incr}>ChildC</button>;
};

export const MyApp = () => {
  const dispatch = useAppDispatch();

  const count = useAppSelector((state) => state.counter.value);

  const incr = useCallback(() => {
    dispatch(increment());
  }, [dispatch]);

  return (
    <div>
      <button onClick={incr}>MyApp</button>

      <ChildA />
      <ChildB />
      <ChildC />

      <div>{count}</div>
    </div>
  );
};

But what if I do this? See:

export const glo: {
  dispatch: ReturnType<typeof useAppDispatch>;
} = {
  // @ts-ignore
  dispatch: null
};

const ChildA = () => {
  const incr = useCallback(() => {
    glo.dispatch(increment());
  }, []);

  return <button onClick={incr}>ChildA</button>;
};

const ChildB = () => {
  const incr = useCallback(() => {
    glo.dispatch(increment());
  }, []);

  return <button onClick={incr}>ChildB</button>;
};

const ChildC = () => {
  const incr = useCallback(() => {
    glo.dispatch(increment());
  }, []);

  return <button onClick={incr}>ChildC</button>;
};

export const MyApp = () => {
  const dispatch = useAppDispatch();
  glo.dispatch = dispatch;
  if (!glo.dispatch) {
    throw new Error("dispatch is falsy");
  }

  const count = useAppSelector((state) => state.counter.value);

  const incr = useCallback(() => {
    glo.dispatch(increment());
  }, []);

  return (
    <div>
      <button onClick={incr}>MyApp</button>

      <ChildA />
      <ChildB />
      <ChildC />

      <div>{count}</div>
    </div>
  );
};

After my testing, it also works well. Please tell me why I should do it the usual way? Now the new code (the glo based code) is bigger, but that's because we only have 3 subcomponents. When we have 30+ subcomponents, the glo based code will be much smaller and easier to understand.

Here are the differences:

https://i.ibb.co/tKWv2Qc/image.png

This is the CodeSandbox link:

https://codesandbox.io/s/clever-monad-c99q3k?file=/src/features/index.tsx

P粉291886842P粉291886842239 days ago448

reply all(1)I'll reply

  • P粉845862826

    P粉8458628262024-03-29 12:59:55

    For example, this dispatch function will change in your test.

    Doing this in some environments without testing isn't a "bug" per se, but it's not a big win either.
    If you have the line const dispatch = useAppDispatch(); in your application, then most likely, when the js package is gziped (which is normal nowadays), it will gzip to 3 or 4 anyway byte.

    If you really want to remove the code here, remove useCallback as it is completely unnecessary when passing the callback directly to html.

    reply
    0
  • Cancelreply