“Managing Global State in React Native with Expo: A Developer’s Guide to Seamless App Control”

Covenant Ifeoluwa
3 min readAug 14, 2023

--

Global state management plays a crucial role in ensuring that data remains consistent and accessible across various parts of a React Native application. One popular approach to achieve this is by using libraries like Redux or MobX. However, Expo, a framework for building React Native applications, (If you will like to check how to set up your expo app click here ) also offers a built-in solution for global state management using the useReducer and useContext hooks. In this article, we’ll explore how to effectively manage the global state using these hooks in an Expo project. However, this article is a continuation of the series on guiding young developers on how to acheive a seamless app control by learning basic concepts. You can check the previous article here

Why Global State?

In React Native apps, there are often instances where multiple components need access to the same data or state. Passing data through props between deeply nested components can become unwieldy and lead to prop drilling. Global state management helps to centralize this data and make it available throughout the app without the need for excessive prop passing.

The useReducer and useContext Hooks in Expo:

Expo provides a way to manage global state using the useReducer and useContext hooks, along with the createContext function. This combination allows us to create a global context that encapsulates the state and provides a dispatch function to update the state. Let’s illustrate this with an example.

Setting Up the Global State:

Assume we’re building a simple task management app using Expo. We want to manage a list of tasks that can be added, marked as complete, or removed. Here’s how we can set up the global state:

// TaskContext.js
import React, { createContext, useContext, useReducer } from 'react';

const TaskContext = createContext();

const initialState = {
tasks: [],
};

const taskReducer = (state, action) => {
switch (action.type) {
case 'ADD_TASK':
return {
...state,
tasks: [...state.tasks, action.payload],
};
case 'TOGGLE_TASK':
return {
...state,
tasks: state.tasks.map(task =>
task.id === action.payload
? { ...task, completed: !task.completed }
: task
),
};
case 'REMOVE_TASK':
return {
...state,
tasks: state.tasks.filter(task => task.id !== action.payload),
};
default:
return state;
}
};

export const TaskProvider = ({ children }) => {
const [state, dispatch] = useReducer(taskReducer, initialState);

return (
<TaskContext.Provider value={{ state, dispatch }}>
{children}
</TaskContext.Provider>
);
};

export const useTaskContext = () => useContext(TaskContext);

Using the Global State: With the TaskProvider in place, we can now access and modify the global state within any component using the useTaskContext hook. Here's an example of how we can use it:

// TaskList.js
import React from 'react';
import { FlatList, Text, TouchableOpacity, View } from 'react-native';
import { useTaskContext } from './TaskContext';

const TaskList = () => {
const { state, dispatch } = useTaskContext();

const toggleTask = id => {
dispatch({ type: 'TOGGLE_TASK', payload: id });
};

const removeTask = id => {
dispatch({ type: 'REMOVE_TASK', payload: id });
};

return (
<FlatList
data={state.tasks}
keyExtractor={task => task.id.toString()}
renderItem={({ item }) => (
<View>
<TouchableOpacity onPress={() => toggleTask(item.id)}>
<Text style={{ textDecorationLine: item.completed ? 'line-through' : 'none' }}>
{item.text}
</Text>
</TouchableOpacity>
<TouchableOpacity onPress={() => removeTask(item.id)}>
<Text>Remove</Text>
</TouchableOpacity>
</View>
)}
/>
);
};

export default TaskList;

Integrating the Global State in the App: To integrate the global state into your app, wrap your app’s root component with the TaskProvider:

// App.js
import React from 'react';
import { TaskProvider } from './TaskContext';
import TaskList from './TaskList';

const App = () => {
return (
<TaskProvider>
<TaskList />
</TaskProvider>
);
};

export default App;

Conclusion: Expo’s use of the useReducer and useContext hooks, in conjunction with the createContext function, offers an effective way to manage global state in React Native applications. By centralizing data and state management, you can build more maintainable and organized apps. This approach avoids prop-drilling and promotes a cleaner architecture. As you continue your journey as a Software Engineer, integrating global state management techniques like this in your Expo projects can significantly enhance your development process and the overall quality of your applications.

--

--