Created
February 3, 2020 03:10
-
-
Save nluo/71b2beb595f6960fadc238e0069c7ee8 to your computer and use it in GitHub Desktop.
React memo examples
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This is working as designed. There is a longer discussion about this in #14110 if you're curious. | |
Let's say for some reason you have AppContext whose value has a theme property, and you want to only re-render some ExpensiveTree on appContextValue.theme changes. | |
TLDR is that for now, you have three options: | |
Option 1 (Preferred): Split contexts that don't change together | |
If we just need appContextValue.theme in many components but appContextValue itself changes too often, we could split ThemeContext from AppContext. | |
function Button() { | |
let theme = useContext(ThemeContext); | |
// The rest of your rendering logic | |
return <ExpensiveTree className={theme} />; | |
} | |
Now any change of AppContext won't re-render ThemeContext consumers. | |
This is the preferred fix. Then you don't need any special bailout. | |
Option 2: Split your component in two, put memo in between | |
If for some reason you can't split out contexts, you can still optimize rendering by splitting a component in two, and passing more specific props to the inner one. You'd still render the outer one, but it should be cheap since it doesn't do anything. | |
function Button() { | |
let appContextValue = useContext(AppContext); | |
let theme = appContextValue.theme; // Your "selector" | |
return <ThemedButton theme={theme} /> | |
} | |
const ThemedButton = memo(({ theme }) => { | |
// The rest of your rendering logic | |
return <ExpensiveTree className={theme} />; | |
}); | |
Option 3: One component with useMemo inside | |
Finally, we could make our code a bit more verbose but keep it in a single component by wrapping return value in useMemo and specifying its dependencies. Our component would still re-execute, but React wouldn't re-render the child tree if all useMemo inputs are the same. | |
function Button() { | |
let appContextValue = useContext(AppContext); | |
let theme = appContextValue.theme; // Your "selector" | |
return useMemo(() => { | |
// The rest of your rendering logic | |
return <ExpensiveTree className={theme} />; | |
}, [theme]) | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment