Movatterモバイル変換


[0]ホーム

URL:


Mark's Dev Blog

Random musings on React, Redux, and more, by Redux maintainer Mark "acemarke" Erikson
 Sponsor @markerikson
 Home

Blogged Answers: React, Redux, and Context Behavior

Posted on
#javascript#react#redux#greatest-hits

This is a post in theBlogged Answers series.


An explanation of how React Context behaves, and how React-Redux uses Context internally

There's a couple assumptions that I've seen pop up repeatedly:

Both of these assumptions are incorrect, and I want to clarify how they actually work so that you can avoid mis-using them in the future.

For context behavior, say we have this initial setup:

function ProviderComponent() {    const [contextValue, setContextValue] = useState({a: 1, b: 2});    return (        <MyContext.Provider value={contextValue}>            <SomeLargeComponentTree />        </MyContext.Provider>    )}function ChildComponent() {    const {a} = useContext(MyContext);    return <div>{a}</div>}

If theProviderComponent were to then callsetContextValue({a: 1, b: 3}),theChildComponentwould re-render, even though it only cares about thea field based on destructuring. It also doesn't matter how many levels of hooks are wrapping thatuseContext(MyContext) call. A new reference was passed into the provider, soall consumers will re-render. In fact, if I were to explicitly re-render with<MyContext.Provider value={{a: 1, b: 2}}>,ChildComponent wouldstill re-render because a new object reference has been passed into the provider! (Note that this is why you should never pass object literals directly into context providers, but rather either keep the data in state or memoize the creation of the context value.)

For React-Redux: yes, ituses context internally,but only to pass the Redux storeinstance down to child components - it doesn't passthe store state using context!. If you look at the actual implementation, it's roughly this but with more complexity:

function useSelector(selector) {    const [, forceRender] = useReducer( counter => counter + 1, 0);    const {store} = useContext(ReactReduxContext);            const selectedValueRef = useRef(selector(store.getState()));    useLayoutEffect(() => {        const unsubscribe = store.subscribe(() => {            const storeState = store.getState();            const latestSelectedValue = selector(storeState);            if(latestSelectedValue !== selectedValueRef.current) {                 selectedValueRef.current = latestSelectedValue;                 forceRender();            }        })                return unsubscribe;    }, [store])    return selectedValueRef.current;}

So,React-Redux only uses context to pass the store itself down, and then usesstore.subscribe() to be notified when the store state has changed. This results in very different performance behavior than using context to pass data.

There was an extensive discussion of context behavior inReact issue #14110: Provide more ways to bail out of hooks. In that thread,Sebastian Markbage specifically said:

My personal summary is that new context is ready to be used for low frequency unlikely updates (like locale/theme). It's also good to use it in the same way as old context was used. I.e. for static values and then propagate updates through subscriptions. It's not ready to be used as a replacement for all Flux-like state propagation.

In fact, wedid try to pass the store state in context in React-Redux v6, and it turned out to be insufficiently performant for our needs,which is why we had to rewrite the internal implementation to use direct subscriptions again in React-Redux v7.

For complete detail on how React-Redux actually works, read my postThe History and Implementation of React-Redux, which covers the changes to the internal implementation over time, and how we actually use context.


This is a post in theBlogged Answers series.Other posts in this series:

Recent Posts

Presentations: The State of React and the Community in 2025The State of React and the Community in 2025Presentations: Maintaining a Library and a CommunityReact Advanced 2024: Designing Effective DocumentationReact Summit 2024: Why Use Redux Today?

Top Tags

63 redux56 javascript49 react31 presentation30 greatest-hits

Greatest Hits

Greatest Hits: The Most Popular and Most Useful Posts I've WrittenRedux - Not Dead Yet!Why React Context is Not a "State Management" Tool (and Doesn't Replace Redux)A (Mostly) Complete Guide to React Rendering BehaviorPresentations: Modern Redux with Redux ToolkitWhen (and when not) to reach for ReduxThe Tao of Redux, Part 1 - Implementation and IntentThe History and Implementation of React-ReduxThoughts on React Hooks, Redux, and Separation of ConcernsReact Boston 2019: Hooks HOCs, and TradeoffsUsing Git for Version Control Effectively

Series

21 Blogged Answers4 Codebase Conversion4 Coding Career Advice2 Declaratively Rendering Earth In 3d5 How Web Apps Work8 Idiomatic Redux6 Newsletter13 Practical Redux32 Presentations5 Site Administrivia

[8]ページ先頭

©2009-2025 Movatter.jp