2020-02-04
1349
#react
Ibrahima Ndaw
13519
Feb 4, 2020 ⋅ 4 min read

Pitfalls of overusing React Context

Ibrahima Ndaw JavaScript enthusiast, full-stack developer, and blogger who also dabbles in UI/UX design.

Recent posts:

chatgpt atlas for developers featured image

How to use ChatGPT Atlas for frontend debugging, testing, and more

Learn how ChatGPT’s new browser Atlas fits into a frontend developer’s toolkit, including the debugging and testing process.

Emmanuel John
Nov 20, 2025 ⋅ 10 min read

Why composition – not reactivity – leads UI’s future

Users don’t think in terms of frontend or backend; they just see features. This article explores why composition, not reactivity, is becoming the core organizing idea in modern UI architecture.

Oscar Jite-Orimiono
Nov 20, 2025 ⋅ 6 min read
the replay nov 19

The Replay (11/19/25): React 19.2 async, GitHub Octoverse, and more

Discover what’s new in The Replay, LogRocket’s newsletter for dev and engineering leaders, in the November 19th issue.

Matt MacCormack
Nov 19, 2025 ⋅ 33 sec read

React 19.2: The async shift is finally here

Jack Herrington writes about how React 19.2 rebuilds async handling from the ground up with use(), , useTransition(), and now View Transitions.

Jack Herrington
Nov 19, 2025 ⋅ 5 min read
View all posts

14 Replies to "Pitfalls of overusing React Context"

  1. How about using three different context(for value, increment and decrement) that value object will not recreated every time count value is changed thus stop unnecessary re-rendering of child nodes

    import React, { useState, useContext, useCallback } from “react”;

    const CounterContext = React.createContext();
    const CounterIncreaseAction = React.createContext();
    const CounterDecreaseAction = React.createContext();

    const CounterProvider = ({ children }) => {
    const [count, setCount] = useState(0);

    const incerement = useCallback(() => setCount(prev => prev + 1), []);
    const decrement = useCallback(() => setCount(prev => prev – 1), []);

    return (

    {children}

    );
    };

    export const useCounter = () => useContext(CounterContext);
    export const useCounterIncrease = () => useContext(CounterIncreaseAction);
    export const useCounterDecrease = () => useContext(CounterDecreaseAction);

    export default CounterProvider;

    and

    import React from “react”;
    import ReactDOM from “react-dom”;
    import CounterProvider, {
    useCounter,
    useCounterIncrease,
    useCounterDecrease
    } from “./counter-provider”;

    const IncrementCounter = () => {
    console.log(“inceremtn rendered”);
    const incerement = useCounterIncrease();
    return Increment;
    };

    const DecrementCounter = () => {
    console.log(“decrement rendered”);
    const decrement = useCounterDecrease();
    return Decrement;
    };

    const ShowResult = () => {
    console.log(“result rendered”);
    const count = useCounter();
    return {count};
    };

    const App = () => (

    );

  2. Shouldn’t setCount also be part of the memoization (note the intentional spelling here) since it’s created on a component render/re-render?

  3. This would be a problem if `setCount` refered to the value itself, `count` which would refer to the value inside the original function definition closure. Instead, they’ve used a callback setter which is going to get the fresh value as it’s argument every time.

    `setCount(count + 1)` counter + 1)` <– guaranteed fresh.

    The best way to keep track of these type of pitfalls? Use the react hooks eslint plugin!

  4. Hello,
    Our project has a “multi-step” form, each step may be saved independently with PATCH requests.
    At the end of each step, two buttons: prev / next(and save)
    On the left side there’s a sidebar where each step shows if it was saved or is yet to complete. When a step is completed you can click it and navigate to it.
    But if your current form is dirty you’ll be asked to save or discard.
    The issue is, the component that “knows you are leaving”, is independent from the multiple forms being replaced one after the other in the “form area”.
    So we have a solution to, upon each Formik render, “observe” its state (i.e. values, dirty, isValid) and lift it up to the store. So the sidebar shows if the step you are is dirty, and also upon clicking on the other steps, if dirty, you get prompted.
    We try to leave Redux behind and when trying to migrate this to another solution it gets very complicated. Redux seems smart enough in its memoized selectors and batched dispatches to prevent extra renders. And since we are dispatching on every Formik render (since Formik itself has no other way to be globally “observed”), a solution based on Context API quickly tears to pieces.
    What’s your opinion given this use case. Should we stick to Redux?
    Thanks!

    1. I think you could have a global state (in the Context) only with the general status of each step (completed, unsaved, etc).
      Then, you could use one “Formik” form for each step (with its own state, isDirty, isValidated, submit button, etc), handled inside each step component, that will also make the PATCH calls.
      After each step submission or “leaved without saving”, this global status data could be updated in the Context by calling an update function (you can pass callback functions in the Context value, so they can be accessible everywhere is needed).

  5. @Martin it sounds like it’s a little agnostic to your exact state management solution, but I have a bias. Been working on a wrapper around react-hook-form which basically makes it easy to use RHF and follow the company’s design conventions. The general idea here is to put a cap on the firehose. The firehose being the most noisy event wise. Of course, RHF does this itself quite well, but in our company’s forms, we need to enable the submit button ONLY if EVERY input value in the form is valid. What this looks like for me, is memoizing based on the final determined form validity/submitBtn enabled state.

    So, identify the most noisy part of the code, that’s firing the most events, and extract out exactly the data you need for the sidebar, and memoize based on that extracted data.
    So, you have values, dirty, isValid values you are receiving from formik (your firehose, if I’m thinking about your issue correctly)
    Then what you need to know in the sidebar: Some sort of list of the Form Steps saved/incomplete status.
    In abstract terms, you need to put a cap on the firehose.
    `values` changes on every keystroke.
    isFormCompleted changes quite infrequently.
    It’s hard to get much more specific, but you would then `useMemo` to avoid any un-necessary cascading due to `values` constantly changing (cascade of change would only happen when isFormCompleted/isFormDirty changes)

    1. Hey Devin, thanks for the comment. It sounds like your solution with the RHF wrapper could be really helpful for other devs as well. Would you be interested in writing a post on it for the LogRocket blog? Let me know — mangelosanto[at]logrocket[dot]com

  6. Can’t see how the same problems that existed with Redux are solved using reselect, for example. Seems like you are bundling multiple states that don’t share the same context into one provider.

  7. I think the issue would be if you use only 1 Provider for all your states. You are supposed to use 1 Provider for each resource/entity of your state, as you would do with reducers in the Redux.
    But, for large applications, it would be too many Providers, then Redux is the best option. The new Redux Toolkit made it even easier to setup the store and have “slices” of your data (also, it has RTK Query to manage API calls).

  8. why do the React developers create unstable, unusable stuff. I am frankly pissed out at so many calls. Even though react is beautiful it sucks when there are performance issues becuase developers did not think it through.

Leave a Reply

Would you be interested in joining LogRocket's developer community?

Join LogRocket’s Content Advisory Board. You’ll help inform the type of content we create and get access to exclusive meetups, social accreditation, and swag.

Sign up now