Description
Hi,
first of all wonderful light implementation of this useful "tool".
I tried this lib with a simple code with a context provider component (PreferencesProvider
with value = object with 2 properties: lang and theme), 2 context consumer components that respectively subscribe one of the 2 "context props" (LangConsumer
and ThemeConsumer
) and the main screen component StubScreen
that only subscribe the context setter function.
On react-native 0.64 code works as expected: when I update only one property (ie. lang) it rerender only the context provider and the LangConsumer component, instead on react-native 0.68 the same code rerenders all consumers: LangConsumer, ThemeConsumer and StubScreen too, no caring of which context property I updated.
I guess that the non-documented feature available on React.createContext API which allows us to disable dispatching updates to every component accessing a Context value
isn't available anymore on new react-native release...
ENVIRONMENT INFO:
- macOs 11.6
- jdk 11.0.6-zulu
- Android Studio 2020.3.1 patch 4
- NPM 8.1.4
- Node.js 17.2.0
- react-native 0.64.2 (react 17.0.1) & 0.68.0 (react 17.0.2)
- Android Emulator API 30 + physical device Android 11 (API 30)
Below sample code:
import React, { useState, useCallback } from 'react';
import { StyleSheet, View, Text, Button } from 'react-native';
import { createContext, useContextSelection } from 'use-context-selection';
export default App;
// CONTEXT PROVIDER
const PreferencesContext = createContext();
const PreferencesProvider = ({children}) => {
const [preferences, setPreferences] = useState({theme: 'light', lang: 'it'});
const contextValue = {preferences, setPreferences};
console.debug("render: PreferencesProvider");
return (
<PreferencesContext.Provider value={contextValue}>
{children}
</PreferencesContext.Provider>
);
};
// CONTEXT CONSUMERS
const LangConsumer = () => {
const lang = useContextSelection(PreferencesContext, ({preferences}) => preferences.lang);
console.debug("render: LangConsumer");
return (
<Text>Language: {lang}</Text>
);
}
const ThemeConsumer = () => {
const theme = useContextSelection(PreferencesContext, ({preferences}) => preferences.theme);
console.debug("render: ThemeConsumer");
return (
<Text>Theme: {theme}</Text>
);
}
const StubScreen = () => {
const setPreferences = useContextSelection(PreferencesContext, ({setPreferences}) => setPreferences )
const toggleTheme = useCallback(
() => setPreferences(state => ({
...state,
theme: (state.theme === 'light' ? 'dark' : 'light'),
})),
[]
);
const toggleLang = useCallback(
() => setPreferences(state => ({
...state,
lang: (state.lang === 'it' ? 'en' : 'it')
})),
[]
);
console.debug("render: StubScreen");
return (
<View style={styles.stubView}>
<ThemeConsumer />
<Button onPress={toggleTheme} title="Change Theme" />
<LangConsumer />
<Button onPress={toggleLang} title="Change Language" />
</View>
);
}
// ROOT COMPONENT
function App() {
console.debug("render: App");
return (
<PreferencesProvider>
<StubScreen />
</PreferencesProvider>
);
}
// STYLES
const styles = StyleSheet.create({
stubView: {
flex: 1,
justifyContent: 'center',
alignItems: 'center'
},
});