DEV Community

Cover image for React Native State Management: The Ultimate Guide [2024]
Alexander Samuel
Alexander Samuel

Posted on

React Native State Management: The Ultimate Guide [2024]

Building an app with big ideas, multiple users and screens with React Native. You must look into a very important factor - State Management.

You’ll handle data across several components. You will need tools to make it easier to display, share, and update those data throughout the app, right? This is where state management comes into play.

This article is aimed at educating business owners and developers on the importance of State Management to create powerful enterprise apps.

React Native State Management: An Overview

React Native State Managemen
For people new to React Native, managing state can be tricky at first. But don't worry! Good state management takes care of how your app looks, how data is managed and most importantly, it prevents losing important data when developing complex apps.

Now, there are many tools out there that help developers share data between different parts of their apps.

Some of the popular ones are Redux, Recoil, and Hooks, in the npm registry.

Each of these tools is quite unique and when picking one of them, you must clearly think about what your project needs are. Typically, your choice should depend on what you want your app to do.

React Native State Management Libraries

React Native State Management Libraries
State management libraries are really helpful for big, and complex React Native apps.

Here’s how these libraries become a big plus when you are building apps:
Your app will have many parts. These libraries will help these parts work together.

It’s easy to fetch data from different parts of the app, with these tools.

They are particularly very helpful when building complex apps.
Now, let’s quickly look into these libraries and how they are actually helpful for your app.

1.Context API

React usually passes data from parent to child components using props. Sometimes, you need to send data to deeply nested components, which can be tedious. The Context API solves this problem by creating a kind of "global" state for a part of your app.

It's like setting up a direct line of communication between distant components. You create a "context" which holds the data you want to share. A "Provider" component wraps the part of your app that needs access to this data. Any component inside the Provider can then access this data directly, without passing props. This makes it easier to share data across many components without extra code.

Let's use a simple example to illustrate how the Context API works:

Imagine we're building a small app that has a theme (light or dark) that needs to be accessed by multiple components. Here's how we might set this up using the Context API:

1. First, we create a context:
Let’s create a context ThemeContext with a default value of 'light'.

import React from 'react';

const ThemeContext = React.createContext('light');
Enter fullscreen mode Exit fullscreen mode

2. Then, we create a provider component:
In our App component, we wrap Toolbar with ThemeContext.Provider, setting the value to 'dark'.

function App() {
  return (
    <ThemeContext.Provider value="dark">
      <Toolbar />
    </ThemeContext.Provider>
  );
}

Enter fullscreen mode Exit fullscreen mode

3. Now, we can use this context in a deeply nested component:

The Button component, which is nested inside Toolbar, can now access this theme value directly using ThemeContext.Consumer. We didn't need to pass the theme as a prop through the Toolbar to get it to Button.

function Button() {
  return (
    <ThemeContext.Consumer>
      {theme => <button className={theme}>I'm a {theme} theme button</button>}
    </ThemeContext.Consumer>
  );
}

function Toolbar() {
  return (
    <div>
      <Button />
    </div>
  );
}
Enter fullscreen mode Exit fullscreen mode

This is a simple example, but it demonstrates how Context can be used to avoid "prop drilling" (passing props through multiple levels) and make certain data available to many components at once.

Here's what you should know about Context API:

  1. It lets you share data without passing it through every level of your app.
  2. Context API makes your code cleaner and easier to read.
  3. It's great for sharing information that many parts of your app need, like user details or app settings.
  4. You can use it to create variables that work everywhere in your app.
  5. It's especially helpful when you need to send data to parts of your app that are deeply nested.
  6. Context API is simpler to use compared to some other state management tools.
  7. It's good for managing state in big business apps.
  8. You can use it to share things like the current user, the app's theme, or language settings. Overall, Context API is a user-friendly way to manage state in React Native, especially for larger apps.

Easy-peasy

Easy-Peasy is a tool for managing state in React Native apps. Just like its name, It's designed to be simpler to use than other state management libraries. Believe me, you'll write less code with Easy-Peasy compared to other methods.

Easy-Peasy works well with React hooks, which are a modern way to use state in React. It also supports Redux middleware, allowing for more advanced features, which helps developers to create and expand their app's data store. Under the hood, Easy-Peasy uses Redux to handle the state.

I'll use the same theme example we discussed earlier for the Context API, but this time I'll explain how Easy-Peasy works here.

First, let's set up our store with Easy-Peasy:

We create a store with a theme state and a setTheme action.

import { createStore, action } from 'easy-peasy';

const store = createStore({
  theme: 'light',
  setTheme: action((state, payload) => {
    state.theme = payload;
  }),
});
Enter fullscreen mode Exit fullscreen mode

Now, let's create our components:
The App component wraps everything in a StoreProvider, giving all

  • components access to the store.
  • The Button component uses useStoreState to access the current theme directly.
  • The Toolbar component also accesses the theme, and uses useStoreActions to get the setTheme function.
  • We add a "Toggle Theme" button in the Toolbar that switches between light and dark themes.
  • When you press the toggle button, it calls the setTheme action to update the state.
  • All components using the theme automatically update when it changes.
import React from 'react';
import { View, Text, Button } from 'react-native';
import { StoreProvider, useStoreState, useStoreActions } from 'easy-peasy';

function Button() {
  const theme = useStoreState(state => state.theme);
  return (
    <Button 
      title={`I'm a ${theme} theme button`}
      color={theme === 'light' ? 'black' : 'white'}
    />
  );
}

function Toolbar() {
  const theme = useStoreState(state => state.theme);
  const setTheme = useStoreActions(actions => actions.setTheme);

  const toggleTheme = () => {
    setTheme(theme === 'light' ? 'dark' : 'light');
  };

  return (
    <View>
      <Button />
      <Button title="Toggle Theme" onPress={toggleTheme} />
    </View>
  );
}

function App() {
  return (
    <StoreProvider store={store}>
      <Toolbar />
    </StoreProvider>
  );
}

export default App;
Enter fullscreen mode Exit fullscreen mode

Compared to the Context, this is how Easy peasy differs:

  1. We don't need to create separate Provider and Consumer components.
  2. State and actions are defined in one place (the store).
  3. Components can easily access and modify the state using hooks.
  4. We get built-in state management features like actions and computed properties.

Wrapping up, here’s what you should know about Easy Peasy

  1. Easy-Peasy makes managing states simple in React Native.
  2. It requires less code than other libraries.
  3. It combines different state management methods.
  4. Easy-Peasy works well with React Hooks and Redux.
  5. It's good for making your app's store better.
  6. It simplifies the state management process.
  7. Easy-Peasy is easy to understand and use

Mobx

MobX is a tool for managing state in applications. Its main goal is to keep your app's data consistent at all times. MobX works by automatically updating everything that depends on your app's state.

When you change some data, MobX figures out what else needs to change as a result. It does this updating for you, so you don't have to write code to update every part manually. This means your app's state (data) and what's shown on screen stay in sync automatically.

Now, let me explain Mobx with the same example,

Here's how we might implement our theme switcher using MobX:

import React from 'react';
import { View, Text, Button } from 'react-native';
import { makeAutoObservable } from 'mobx';
import { observer } from 'mobx-react-lite';

// Create a store
class ThemeStore {
  theme = 'light';

  constructor() {
    makeAutoObservable(this);
  }

  toggleTheme() {
    this.theme = this.theme === 'light' ? 'dark' : 'light';
  }
}

const themeStore = new ThemeStore();

// Create components
const ThemedButton = observer(() => {
  return (
    <Button 
      title={`I'm a ${themeStore.theme} theme button`}
      color={themeStore.theme === 'light' ? 'black' : 'white'}
    />
  );
});

const Toolbar = observer(() => {
  return (
    <View>
      <ThemedButton />
      <Button title="Toggle Theme" onPress={() => themeStore.toggleTheme()} />
    </View>
  );
});

function App() {
  return <Toolbar />;
}

export default App;
Enter fullscreen mode Exit fullscreen mode

Here's how this MobX works in this example:

  1. We create a ThemeStore class to manage our theme state.
  2. makeAutoObservable tells MobX to track all properties and methods in this class.
  3. The theme property holds our current theme state.
  4. toggleTheme is a method that switches the theme.
  5. We create a single instance of ThemeStore called themeStore.
  6. Components are wrapped with observer, which makes them react to changes in observed data.
  7. ThemedButton and Toolbar components directly use themeStore to access the current theme.
  8. When the "Toggle Theme" button is pressed, it calls themeStore.toggleTheme().
  9. MobX automatically updates all components that depend on the theme when it changes.

How does Mobx differ from the above explained tools?

  1. With MobX, we don't need to wrap our app in a provider component.
  2. State is encapsulated in a class, which can include both data and methods to modify that data.
  3. Components become reactive automatically when wrapped with an observer.
  4. MobX handles all the updates behind the scenes, so we don't need to manually trigger re-renders.

In a nutshell, there are some of the key information you need to know about Mobx

  1. Mobx uses simple code for state management.
  2. It's similar to regular JavaScript, so it's familiar.
  3. You don't need to learn a new system like with Redux.
  4. Mobx helps manage state across your whole app.
  5. It can update the state quietly when needed.
  6. Mobx is good for big, complex apps.
  7. It makes writing and testing code easier.

Recoil

Recoil is a new tool for managing state in React apps, especially larger ones. It aims to solve problems that developers face when using React's built-in Context API.

Recoil has two main parts: atoms and selectors.

Atoms are the basic units of state in Recoil. They can be updated and the components can subscribe to atoms. When an atom changes, all components using it update automatically

Selectors are nothing but the functions that can compute values. They can use atoms or other selectors as inputs. They recalculate when their inputs change and can subscribe to selectors too. When a selector changes, components using it update automatically. This can be effective immediately or after a brief delay.

Now, let’s get into the example:

1. Imports:

We import the necessary components from React Native and Recoil. RecoilRoot, atom, and useRecoilState are Recoil-specific imports.

import React from 'react';
import { View, Text, Button } from 'react-native';
import { RecoilRoot, atom, useRecoilState } from 'recoil';
Enter fullscreen mode Exit fullscreen mode

2.Creating an atom:

An atom is Recoil's unit of state. It's similar to a store in MobX. The key must be unique, and default sets the initial value.

const themeState = atom({
  key: 'themeState',
  default: 'light',
});
Enter fullscreen mode Exit fullscreen mode

3.ThemedButton component:

This component uses useRecoilState to read the current theme. It only needs to read, so we destructure just the first element of the returned array.

const ThemedButton = () => {
  const [theme] = useRecoilState(themeState);
  // ...
};
Enter fullscreen mode Exit fullscreen mode

4. Toolbar component:

This component uses useRecoilState to both read and write the theme state. The toggleTheme function uses a functional update to switch the theme based on its current value.

const Toolbar = () => {
  const [theme, setTheme] = useRecoilState(themeState);

  const toggleTheme = () => {
    setTheme(currentTheme => currentTheme === 'light' ? 'dark' : 'light');
  };
  // ...
};
Enter fullscreen mode Exit fullscreen mode

5.App component and RecoilRoot:

function App() {
  return (
    <RecoilRoot>
      <Toolbar />
    </RecoilRoot>
  );
}
Enter fullscreen mode Exit fullscreen mode

The RecoilRoot component must wrap any part of the app that uses Recoil state.

Now, how does Key differences from MobX:

  1. In Recoil, we define atomic units of state using atoms, whereas in MobX we create a class with observable properties.
  2. We use the setter function returned by useRecoilState to update state. In MobX, we define methods in the store to modify state.
  3. Recoil uses hooks like useRecoilState to connect components to state, while MobX uses the observer higher-order component.
  4. Recoil requires wrapping the app in a RecoilRoot, while MobX doesn't require this kind of setup.
  5. Both provide automatic updates when state changes, but they achieve this in different ways under the hood.

Now, there are other interesting things to know about Recoil. Here are some of the key info about this library.

  1. Recoil uses a simple, hooks-based API for state management.
  2. It's designed specifically for React, aligning well with React's principles.
  3. Recoil introduces concepts like atoms and selectors, which are intuitive for React developers.
  4. It allows for efficient, granular updates to your app's state.
  5. Recoil handles asynchronous and derived state with ease.
  6. It's particularly good for apps with complex, interdependent states.
  7. Recoil supports code splitting and lazy loading of state, beneficial for large applications.
  8. It provides built-in dev tools for easier debugging and state visualization.
  9. Recoil makes it simple to share state across components without prop drilling.
  10. It integrates well with React Suspense for handling loading states.

That’s a Wrap!

And now we are here. That’s one deep round up about the state management libraries for React Native app development. Unlike other tech stacks, React Native is highly preferred for complex apps, just because its state management is so good. I hope this gives you a clear picture of the libraries and how exactly they work on your apps.

Now, if you have any queries on this, do feel free to post them in the comments below. My team and I will be more than happy to help you out. Until I meet you with yet another interesting article, stay tuned to my blogs.

Top comments (0)