title: React useContext() performance, useContext inside custom hook
body: <p>I used a structure using <a href="https://reactjs.org/docs/hooks-intro.html" rel="noreferrer">React Hooks</a>. It is based on a global <a href="https://en.reactjs.org/docs/context.html" rel="noreferrer">Context</a> that contains a combination of reducers (as in the Redux).
  Also, I widely use <a href="https://reactjs.org/docs/hooks-custom.html" rel="noreferrer">custom hooks</a> to separate logic.
  I have a hook that contains asynchronous API requests and it has become quite cumbersome and I have the opportunity to split almost every function of this hook into other hooks, but each of these functions uses a global context (more precisely - dispatch from useReducer()).</p>
  
  <h3>So, questions:</h3>
  
  <ol>
  <li>Is it ok to use useContext() in every hook who needs it?</li>
  <li>How will it affect performance if, for example, I create 10 custom hooks that use useContext() internally and use them in the component.</li>
  </ol>
  
  <h3>Example:</h3>
  
  <p>providers/Store.js</p>
  
  <pre><code>import React, { createContext, useReducer } from 'react';
  
  export const StoreContext = createContext();
  
  export const StoreProvider = ({ children }) =&gt; {
    /**
     * Store that contains combined reducers.
     */
    const store = useReducer(rootReducer, initialState);
  
    return (
      &lt;StoreContext.Provider value={store}&gt;{children}&lt;/StoreContext.Provider&gt;
    );
  };
  </code></pre>
  
  <p>hooks/useStore.js</p>
  
  <pre><code>import { useContext } from 'react';
  import { StoreContext } from '../providers';
  
  export const useStore = () =&gt; useContext(StoreContext);
  </code></pre>
  
  <p>hooks/useFoo.js</p>
  
  <pre><code>import { useCallback } from 'react';
  import { useStore } from './useStore';
  
  export const useFoo = () =&gt; {
    const [, dispatch] = useStore();
  
    const doFoo = useCallback(
      async params =&gt; {
        dispatch(actions.request());
  
        try {
          const res = await SomeService.getSomething(params);
          dispatch(actions.add(res));
          dispatch(actions.success());
        } catch (error) {
          dispatch(actions.failure());
        }
      },
      [dispatch]
    );
  
    return { doFoo };
  };
  </code></pre>
  
  <p>hooks/useBar.js</p>
  
  <pre><code>import { useCallback } from 'react';
  import { useStore } from './useStore';
  
  export const useBar = () =&gt; {
    const [, dispatch] = useStore();
  
    const doBar = useCallback(
      async params =&gt; {
        dispatch(actions.request());
  
        try {
          const res = await SomeService.getSomething(params);
          dispatch(actions.success());
          dispatch(actions.add(res));
        } catch (error) {
          dispatch(actions.failure());
        }
      },
      [dispatch]
    );
  
    return { doBar };
  };
  </code></pre>
  
  <p>hooks/useNext.js</p>
  
  <pre><code>...
  import { useStore } from './useStore';
  
  export const useNext = () =&gt; {
    const [, dispatch] = useStore();
  
    ...
  };
  </code></pre>
  
  <p>components/SomeComponent.js</p>
  
  <pre><code>const SomeComponent = () =&gt; {
    // use context
    const [store, dispatch] = useStore();
  
    // and here is the context
    const { doFoo } = useFoo();
  
    // and here
    const { doBar } = useBar();
  
    // and here
    useNext();
  
    return (
      &lt;&gt;
        &lt;Button onClick={doFoo}&gt;Foo&lt;/Button&gt;
        &lt;Button onClick={doBar}&gt;Bar&lt;/Button&gt;
        // the flag is also available in another component
        {store.isLoading &amp;&amp; &lt;Spin /&gt;}
      &lt;/&gt;
    )
  }
  </code></pre>