Search code examples
react-nativereact-reduxopen-sourceexpo

How to get root component to re-render in react-native with redux (Open source project)


How would you get the root component in React-Native (Expo.io) to re-render on state change when using redux?

I'm trying to get <FormattedWrapper locale='en' messages={messages}> to update "locale" when state is changed. I have tried to have a local state in the constructor, use store.getState().language.language, have a local variable which got update in ComponentWillUpdate because of a subscribe function from redux, but nothing works.

I have clean it all up and made a PR to the repo I want to contribute to: https://github.com/ipeedy/react-native-boilerplate/pull/3

The App.js code is here:

import React, { Component } from 'react';
import { StatusBar, Platform } from 'react-native';
import { Provider } from 'react-redux';
import { ThemeProvider } from 'styled-components';
import styled from 'styled-components/native';
import { FormattedWrapper } from 'react-native-globalize';

import messages from './Messages';
import store from './store';

import Navigator from './Navigator';
import { colors } from './utils/constants';

const Root = styled.View`
  flex: 1;
  background-color: ${props => props.theme.PINK_50};
`;

const StatusBarAndroid = styled.View`
  height: 24;
  background-color: ${props => props.theme.PINK_200};
`;

class App extends Component {
  render() {
    return (
      <Provider store={store}>
        <ThemeProvider theme={colors}>
                  <FormattedWrapper locale='en' messages={messages}>
            <Root>
              <StatusBar barStyle='light-content' backgroundColor='transparent' translucent />
              { Platform.OS === 'android' && Platform.Version >= 20 ? <StatusBarAndroid /> : null }
            <Navigator />
          </Root>
                    </FormattedWrapper>
        </ThemeProvider>
      </Provider>
    );
  }
}

export default App;

Thanks in advance for any help! :)


Solution

  • Since you're aleady using react-redux, therefore you can use the connect function of the same library.

    Since Connect requires a new instance of the component that you are using, therefore it can be done as shown below.

    First you need to make a separate component of what's inside your provider and connect it with the store

    For example from what I understand in your code

    import { Provider, connect } from 'react-redux';
    
    class RootContainer extends Component {
      render() {
        const {locale} = this.props
        return (
            <ThemeProvider theme={colors}>
                      <FormattedWrapper locale={locale} messages={messages}>
                <Root>
                  <StatusBar barStyle='light-content' backgroundColor='transparent' translucent />
                  { Platform.OS === 'android' && Platform.Version >= 20 ? <StatusBarAndroid /> : null }
                <Navigator />
              </Root>
                        </FormattedWrapper>
            </ThemeProvider>
        );
      }
    }
    
    const mapState = state = ({
       locale: state.language.language
    })
    
    ConnectedRootContainer =  connect(mapState, null)(RootContainer);
    
    class App extends Component {
      render() {
        return (
          <Provider store={store}>
            <ConnectedRootContainer/>
          </Provider>
        );
      }
    }
    
    export default App;
    

    Or another simple way would be just to make the connected component for the <FormattedWrapper/>