Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

rerenders on RN 0.68 #6

Closed
fondakogb opened this issue Apr 10, 2022 · 3 comments
Closed

rerenders on RN 0.68 #6

fondakogb opened this issue Apr 10, 2022 · 3 comments

Comments

@fondakogb
Copy link

fondakogb commented Apr 10, 2022

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'
  },
});
@edriang
Copy link
Owner

edriang commented Apr 11, 2022

Hello there! Thanks for taking some time to create this issue, and to provide evidence about the issue.

I'm not a RN user and I'm not familiar with the versioning/releases of that library; but after you suggested the issue might be due to the unstable_changedBits property no longer being supported, I checked the React@18 codebase and this was completely removed from there. I believe they probably do the same for RN.

I have asked React team to check if there is any other way to achieve a similar behavior in case there is a way I could re-implement the solution for this library.

I'll wait in the upcoming days for any news about that; if not, then I'll probably mark the library as not supporting React@18 and probably RN@0.68 as you just suggested.

For the moment, you can try downgrading RN library, or explore using use-context-selector library instead.

@edriang
Copy link
Owner

edriang commented Apr 12, 2022

Hello again!, it seems the unstable_changedBits is gone for good, so the this library won't work as expected for newer React versions.

I just updated another project (react-connect-context-hooks@2.0.0-beta ) to use use-context-selector library instead.

If you need to update your React version, I think that should be your best option. The API is pretty much the same, so I believe you should not have any major problem updating; the only big difference I found is that you cannot specify a custom isEqual function, so keep that in mind if you were relying on that.

Good luck!

@fondakogb
Copy link
Author

Thank you very much for investigating.
I tried use-context-selector and I obtained a partial result: if I update the same single prop of the context value (ie. lang), only expected LangConsumer rerenders, but if I do subsequent updates each time on different context value prop (ie. lang, then theme, then lang) the result is that both (meaning all) consumers rerenders... Maybe it's something wrong in the way I use it, it's the same code as above in this "issue".

I found another module that fits my needs (executing same above code it only rerenders expected consumers no care about of props updates order): react-use-context-selector.
Note I had to fork it to modify its dependency of react from 16.* to 17+

@edriang edriang closed this as completed Apr 17, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants