Skip to content
All essays
iOSJanuary 31, 202512 min

React Native State Management: From Context to Redux

Compare state management solutions in React Native. Learn Context API, Redux Toolkit, and when to use each.

Ü
Ümit Uz
Mobile & Full Stack Developer

Context API

Basic Setup

javascript
import { createContext, useContext, useState } from 'react';

const AuthContext = createContext();

export function AuthProvider({ children }) {
  const [user, setUser] = useState(null);

  const login = (userData) => setUser(userData);
  const logout = () => setUser(null);

  return (
    <AuthContext.Provider value={{ user, login, logout }}>
      {children}
    </AuthContext.Provider>
  );
}

export const useAuth = () => useContext(AuthContext);

Usage

javascript
function LoginScreen() {
  const { login } = useAuth();

  return (
    <Button title="Login" onPress={() => login({ name: 'John' })} />
  );
}

Redux Toolkit

Installation

bash
npm install @reduxjs/toolkit react-redux

Setup

javascript
import { configureStore, createSlice } from '@reduxjs/toolkit';

const authSlice = createSlice({
  name: 'auth',
  initialState: { user: null, isAuthenticated: false },
  reducers: {
    login: (state, action) => {
      state.user = action.payload;
      state.isAuthenticated = true;
    },
    logout: (state) => {
      state.user = null;
      state.isAuthenticated = false;
    },
  },
});

export const { login, logout } = authSlice.actions;

const store = configureStore({
  reducer: {
    auth: authSlice.reducer,
  },
});

Provider

javascript
import { Provider } from 'react-redux';

function App() {
  return (
    <Provider store={store}>
      {/* Your app */}
    </Provider>
  );
}

Hooks

javascript
import { useSelector, useDispatch } from 'react-redux';

function ProfileScreen() {
  const { user } = useSelector((state) => state.auth);
  const dispatch = useDispatch();

  return (
    <View>
      <Text>{user?.name}</Text>
      <Button
        title="Logout"
        onPress={() => dispatch(logout())}
      />
    </View>
  );
}

Zustand

Installation

bash
npm install zustand

Store

javascript
import create from 'zustand';

const useAuthStore = create((set) => ({
  user: null,
  isAuthenticated: false,
  login: (user) => set({ user, isAuthenticated: true }),
  logout: () => set({ user: null, isAuthenticated: false }),
}));

Usage

javascript
function LoginScreen() {
  const { login } = useAuthStore();

  return (
    <Button
      title="Login"
      onPress={() => login({ name: 'John' })}
    />
  );
}

Choosing the Right Solution

Use Context API for:

  • Small to medium apps
  • Simple state
  • No complex relationships
  • Performance is not critical

Use Redux Toolkit for:

  • Large apps with complex state
  • Time-travel debugging needed
  • Middleware requirements
  • Team familiar with Redux

Use Zustand for:

  • Simple API
  • Good performance
  • Less boilerplate
  • TypeScript support

Persistence

AsyncStorage with Redux

javascript
import { persistStore, persistReducer } from 'redux-persist';
import AsyncStorage from '@react-native-async-storage/async-storage';

const persistConfig = {
  key: 'root',
  storage: AsyncStorage,
};

const persistedReducer = persistReducer(persistConfig, rootReducer);

const store = configureStore({
  reducer: persistedReducer,
});

const persistor = persistStore(store);

Best Practices

  1. 1Keep state minimal: Only store what's necessary
  2. 2Normalize data: Avoid nested structures
  3. 3Use selectors: Derive state from store
  4. 4Avoid prop drilling: Use context or Redux
  5. 5Persist wisely: Only essential data

Conclusion

Choose state management based on app complexity. Start simple and scale as needed.

Related essays

Next essay
React Native Navigation: Complete Guide to Mobile Navigation