DEV Community

Cover image for Beyond Redux - MobX and Zustand
Gautam Vaja for CodeParrot

Posted on • Originally published at 10xdev.codeparrot.ai

Beyond Redux - MobX and Zustand

A Comparative Guide to MobX and Zustand for Modern Web Applications.

Introduction

State management is a critical component of JavaScript application development, and Redux has been a dominant player in this arena. However, with the evolution of the JavaScript ecosystem, alternatives like MobX and Zustand have emerged, offering different approaches and philosophies. This blog aims to explore these alternatives, shedding light on their features and appropriate use cases.

Brief about Redux

Redux is a state management library that combines Flux architecture with functional programming concepts. Its main feature is the use of a single store as a source of truth, with a state that is immutable. It enforces unidirectional data flow, where state is read-only and changes are made through pure functions called reducers. Changes to the state are done through actions and reducers. Redux is well-suited for complex applications due to its predictable state management, but it often requires more boilerplate code​. For more information visit this blog.

MobX

MobX uses transparent functional reactive programming (TFRP) to make state management simple and scalable. Unlike Redux, it allows for multiple stores and employs mutable state, which can lead to more straightforward state updates but might complicate debugging and testing. Reactions in MobX automatically track changes in observables and update the UI or other parts of the application accordingly. MobX is efficient and performs well, particularly in scenarios where fine-grained event listeners are beneficial.

Internal Structure:

  • Observables: The core of MobX, these are the data structures that store the application's state.
  • Actions: Functions that modify observables. In MobX, actions are not as rigidly structured as in Redux.
  • Computed Values: Derived values that automatically update when their dependencies change.
  • Reactions: Automatic processes that run when observables they depend on change (e.g., re-rendering UI components).

MobX Example:
First, let's set up a basic MobX store for managing a to-do list:

import { makeAutoObservable } from "mobx";

class TodoStore {
  todos = [];

  constructor() {
    makeAutoObservable(this);
  }

  addTodo = (todo) => {
    this.todos.push({ text: todo, completed: false });
  };

  toggleTodo = (index) => {
    this.todos[index].completed = !this.todos[index].completed;
  };
}

export const todoStore = new TodoStore();
Enter fullscreen mode Exit fullscreen mode

Now, we'll use this store in a React component:

import React, { useState } from "react";
import { observer } from "mobx-react-lite";
import { todoStore } from "./TodoStore";

const TodoList = observer(() => {
  const [newTodo, setNewTodo] = useState("");

  const handleSubmit = (e) => {
    e.preventDefault();
    todoStore.addTodo(newTodo);
    setNewTodo("");
  };

  return (
    <div>
      <form onSubmit={handleSubmit}>
        <input
          type="text"
          value={newTodo}
          onChange={(e) => setNewTodo(e.target.value)}
        />
        <button type="submit">Add Todo</button>
      </form>
      <ul>
        {todoStore.todos.map((todo, index) => (
          <li key={index} onClick={() => todoStore.toggleTodo(index)}>
            {todo.text} {todo.completed ? "(completed)" : ""}
          </li>
        ))}
      </ul>
    </div>
  );
});

export default TodoList;
Enter fullscreen mode Exit fullscreen mode

For more code examples visit the documentation here.

Zustand

Zustand is a minimalistic state management solution known for its simplicity and ease of use. It's lightweight and performs well in smaller projects or for developers who prefer a more straightforward solution. While it lacks the extensive ecosystem and community support of Redux, Zustand's simplicity makes it a good choice for projects where a more structured and opinionated approach like Redux is not necessary​

Internal Structure:

  • Store: A small, flexible state container. Each store is a hook itself.
  • Set Function: Used to update the state directly, without the need for actions or reducers.
  • Selectors: Functions to select a part of the state and subscribe components to changes in that part.

Zustand Example:
First, let's create a Zustand store:

import create from "zustand";

const useStore = create((set) => ({
  todos: [],
  addTodo: (todo) =>
    set((state) => ({
      todos: [...state.todos, { text: todo, completed: false }],
    })),
  toggleTodo: (index) =>
    set((state) => {
      const newTodos = [...state.todos];
      newTodos[index].completed = !newTodos[index].completed;
      return { todos: newTodos };
    }),
}));

export default useStore;
Enter fullscreen mode Exit fullscreen mode

Now, we'll use the Zustand store in a React component:

import React, { useState } from "react";
import useStore from "./TodoStore";

const TodoList = () => {
  const [newTodo, setNewTodo] = useState("");
  const { todos, addTodo, toggleTodo } = useStore();

  const handleSubmit = (e) => {
    e.preventDefault();
    addTodo(newTodo);
    setNewTodo("");
  };

  return (
    <div>
      <form onSubmit={handleSubmit}>
        <input
          type="text"
          value={newTodo}
          onChange={(e) => setNewTodo(e.target.value)}
        />
        <button type="submit">Add Todo</button>
      </form>
      <ul>
        {todos.map((todo, index) => (
          <li key={index} onClick={() => toggleTodo(index)}>
            {todo.text} {todo.completed ? "(completed)" : ""}
          </li>
        ))}
      </ul>
    </div>
  );
};

export default TodoList;
Enter fullscreen mode Exit fullscreen mode

For more code examples visit the documentation here

Section 4: Comparison and Use Cases

Feature / Aspect Redux MobX Zustand
Philosophy Predictable state container Reactive state management Minimalistic state management
State Management Unidirectional, centralized Observable, decentralized Simplistic, decentralized
Boilerplate High (actions, reducers, middleware) Low (automatic reactions) Very Low
Learning Curve Steep Moderate Easy
Performance Good for large-scale apps Optimized for individual components Fast for small to medium apps
Scalability Highly scalable Scalable with complexity Best for small to medium projects
Flexibility Structured, less flexible Highly flexible Extremely flexible
Integration Primarily with React, but adaptable Broad (React, Angular, Vue, etc.) Mainly React
Community & Support Very large and established Large and growing Smaller but active
Use Case Large applications with complex state Projects needing fine-grained reactivity Small to medium apps with simple state

Conclusion

  • Use Redux when working on large-scale projects where predictability, maintainability, and scalability are critical. Its structured approach is beneficial for teams needing a robust framework for managing complex state.
  • Use MobX for projects where you need a more straightforward and less boilerplate-heavy approach. It's suitable for applications with complex state changes but where the scale does not justify the overhead of Redux.
  • Use Zustand for smaller projects or when development speed and simplicity are priorities. It's ideal for cases where a lightweight state management solution is sufficient.

Redux is a robust, scalable solution for complex applications, MobX offers simplicity and efficiency for moderate complexity, and Zustand provides minimalism and ease of use for smaller, less complex projects.

Top comments (6)

Collapse
 
lewhunt profile image
Lewis Hunt

Nice comparison, I'm a big fan of Zustand. Used it in all of my recent projects including a large-scale music app deployed on TV devices, performance was great.

Collapse
 
mvaja13 profile image
Gautam Vaja

Sounds good.

Collapse
 
tylerjusfly profile image
Tyler

so you think in like a not so large -scale app performance would still be perfect???

Collapse
 
mvaja13 profile image
Gautam Vaja

yes

Collapse
 
matleo profile image
Mateusz

I disagree on one thing here: Zustand is a hook. It is tied to React component. So I wouldn't call it "Extremely flexible" (in Flexibility category). In case of MobX: stores can be created anywhere, passed anywhere and in any convenient way. It's more flexible in my opinion.

Collapse
 
mvaja13 profile image
Gautam Vaja

Yeah that's true. Thanks for pointing out.