1

Let's say I have a context provider CounterProvider like so:

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

    const setCount = count => {
        typeof count === 'function' && (count = count(data.count));
        setData({ ...data, count });
    };

    return (
        <CounterContext.Provider value={{...data, setCount}}>
            {children}
        </CounterContext.Provider>
    );
};

And a consumer XComp:

const XComp = () => {
    const {count, setCount} = useContext(CounterContext);
    useEffect(() => setCount(count_prev => ++count_prev));
    return <div>XComp</div>;
};

Now, if I use XComp 3 times (ex: *sample-xcomp-usage), CounterProvider state will be {count: 1}. So, it looks like only the first call of setData() in CounterProvider becomes effective.

Now the question(s):

  1. Why does only the first call to setData() seem to be effective?
  2. How can I make every call to setData() effective?

*sample-xcomp-usage:

<InstanceCounterProvider>
    <XComp />
    <XComp />
    <XComp />
</InstanceCounterProvider>

.............

Note: While making this edit, I just realized the "why" and "how".

Answer to question 1:
Component's state changes via setData() are not necessarily applied immediately, rather stored for later update. So subsequent callee setData() does not normally see the changes. Causing the override of stored data. That is why only the first setData() seems to be effective.

Answer to question 2:
React provides an overload of setState() that takes a callback as the argument to produce the changed state. The callback is provided with stored data. So, it is necessary modify the setCount() inside CountProvider like so:

    const setCount = count => {
        setData(data_prev => {
            typeof count === 'function' && (count = count(data_prev.count));
            return { ...data_prev, count };
        };
    };
SDev
  • 11
  • 1
  • 3

0 Answers0