Global state in React Native

Viewed 36921

I am developing a React Native application.

I want to save the user id of the person who is logged in and then check if the user is logged in in every single component.

So what I am looking for is something like cookies, sessions or global states.

I have read that I should use Redux, but this seems to be overly complicated and it is very difficult to make it work with react-navigation. It forces me to define actions and reducers for almost everything although the only thing I want is to be able to access a single global state/variable in all components.

Are there any alternatives or should I really re-structure my entire app to use Redux?

8 Answers

I usually create a global.js containing:

module.exports = {
   screen1: null,
};

And get the value of the state on the screen

import GLOBAL from './global.js'

constructor() {

    GLOBAL.screen1 = this;

}

Now you can use it anywhere like so:

GLOBAL.screen1.setState({
    var: value
});

Update since React 16.8.0 (February 6, 2019) introduce Hooks.

it is not mandatory to use external library like Mobx or Redux. (Before Hook was introduce I used both of this state management solutions)

you can create global state just with 10 line Source

import React, {createContext, useContext, useReducer} from 'react';
export const StateContext = createContext();
export const StateProvider = ({reducer, initialState, children}) =>(
  <StateContext.Provider value={useReducer(reducer, initialState)}>
    {children}
  </StateContext.Provider>
);
export const useStateValue = () => useContext(StateContext);

extend your app with global state:

import { StateProvider } from '../state';

const App = () => {
  const initialState = {
    theme: { primary: 'green' }
  };

  const reducer = (state, action) => {
    switch (action.type) {
      case 'changeTheme':
        return {
          ...state,
          theme: action.newTheme
        };

      default:
        return state;
    }
  };


  return (
    <StateProvider initialState={initialState} reducer={reducer}>
        // App content ...
    </StateProvider>
  );
}

For details explanation I recommend to read this wonderful medium

If you are new to react (as me) and got confused by the first answer. First, use a component Class

export default class App extends React.Component {

constructor(props) {
  super(props);
  this.state = {
    walk: true
  };
  GLOBAL.screen1 = this;
}

render() {
  return (
    <NavigationContainer>
      <Stack.Navigator>
      {this.state.walk ? (
        <>
          <Stack.Screen name="WalkThrough" component={WalkThroughScreen} />
        </>
      ) : (
        <Stack.Screen name="Home" component={HomeScreen} />
      )}
    </Stack.Navigator>
    <StatusBar style="auto" />
  </NavigationContainer>
 )
}

Then you can do in any other component (My components are on /components, global is on root):

import GLOBAL from '../global.js'

GLOBAL.screen1.setState({walk:false})

There appears to be a GLOBAL object. If set in app.js as GLOBAL.user = user, it appears to be available in other components, such as the drawer navigation.

this is an old question but I have a solution that helps me.

To accomplish this, I use what is called a GlobalProvider, essentially provides global data to all components. A lot of this code was learned through YouTube Tutorials so I can not take credit for the ideas. Here is the code,

export const GlobalContext = createContext({});

const GlobalProvider = ({children}) => {
    //authInitialState can be whatever you want, ex: {rand: {}, rand2: null}
    const [authState, authDispatch] = useReducer(auth, authInitialState);

    return (
        <GlobalContext.Provider
            value={{authState, authDispatch}}>
            {children}
        </GlobalContext.Provider>
    );
};

export default GlobalProvider;

Then you would simply wrap your entire application (usually app.js) with GlobalProvider as so. Ignore my AppNavContainer, that just contains code that routes my pages.

import GlobalProvider from "./src/Context/Provider";
const App: () => Node = () => {
    return (
        <GlobalProvider>
            <AppNavContainer/>
        </GlobalProvider>
    );
};

From here on you are able to change the authState with a reducer of some sort, I will not provide that code since it is huge, but look at Soullivaneuh's example on the reducer above.

NOW to the good part, of how to access your state. It is simple, in any component you wish, simply follow a similar structure like this. Notice that I have {data} as it will allow you to see the state.

    const {
        authState: {data},
    } = useContext(GlobalContext);
    
    console.log("Data:", data)

If anyone can correct me where I went wrong, I'd appreciate it as well.

Same as @Brunaine suggested, but I import it only in the App.js and can use it in all the screens.

Related