Skip to content
On this page

Comparison with Other State Libraries

Inglorious Store combines the best aspects of Redux, Redux Toolkit, and game engines. Here's how it compares:

Feature Comparison

FeatureReduxRTKZustandJotaiPiniaMobXInglorious
Boilerplate๐Ÿ”ด High๐ŸŸก Medium๐ŸŸข Low๐ŸŸข Low๐ŸŸก Medium๐ŸŸข Low๐ŸŸข Low
Multiple instances๐Ÿ”ด Manual๐Ÿ”ด Manual๐Ÿ”ด Manual๐Ÿ”ด Manual๐ŸŸก Medium๐ŸŸก Medium๐ŸŸข Built-in
Lifecycle events๐Ÿ”ด No๐Ÿ”ด No๐Ÿ”ด No๐Ÿ”ด No๐Ÿ”ด No๐Ÿ”ด No๐ŸŸข Yes
Async logic๐ŸŸก Thunks๐ŸŸก Complex๐ŸŸข Free๐ŸŸข Free๐ŸŸข Free๐ŸŸข Free๐ŸŸข Native
Redux DevTools๐ŸŸข Yes๐ŸŸข Yes๐ŸŸก Partial๐ŸŸก Partial๐ŸŸก Partial๐ŸŸข Yes๐ŸŸข Yes
Time-travel๐ŸŸข Yes๐ŸŸข Yes๐Ÿ”ด No๐Ÿ”ด No๐Ÿ”ด No๐ŸŸก Limited๐ŸŸข Yes
Testability๐ŸŸข Excellent๐ŸŸข Excellent๐ŸŸก Good๐ŸŸก Good๐ŸŸก Good๐ŸŸก Medium๐ŸŸข Excellent
Immutability๐Ÿ”ด Manual๐ŸŸข Immer๐Ÿ”ด Manual๐Ÿ”ด Manual๐Ÿ”ด Manual๐Ÿ”ด Manual๐ŸŸข Mutative

Detailed Comparison

๐ŸŽฎ Entity Management

Redux/RTK: Managing multiple instances requires reshaping state or creating separate reducers:

javascript
const store = configureStore({
  reducer: {
    workTodos: todosReducer,
    personalTodos: todosReducer,
  },
})

// Adding a new list at runtime is complex
// Requires reducer refactoring or complex middleware
1
2
3
4
5
6
7
8
9

Inglorious Store: Entities are first-class citizens. Add instances at runtime with no code changes:

javascript
const entities = {
  workTodos: { type: "TodoList", todos: [] },
  personalTodos: { type: "TodoList", todos: [] },
}

// Adding new list at runtime
store.notify("add", { id: "projectTodos", type: "TodoList", todos: [] })
1
2
3
4
5
6
7

๐Ÿ“ฆ Boilerplate

Redux: Action creators + reducers + setup

javascript
// Action creators
export const addTodo = (text) => ({ type: "ADD_TODO", payload: text })

// Reducer
const todosReducer = (state = [], action) => {
  switch (action.type) {
    case "ADD_TODO":
      return [...state, { text: action.payload, done: false }]
    default:
      return state
  }
}

// Store
const store = createStore(todosReducer)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

Redux Toolkit: Still boilerplate

javascript
const todosSlice = createSlice({
  name: "todos",
  initialState: [],
  reducers: {
    addTodo: (state, action) => {
      state.push({ text: action.payload, done: false })
    },
  },
})
1
2
3
4
5
6
7
8
9

Inglorious Store: Define types and entities, done

javascript
const types = {
  todoList: {
    addTodo(entity, text) {
      entity.todos.push({ text, done: false })
    },
  },
}

const entities = {
  todos: { type: "TodoList", todos: [] },
}
1
2
3
4
5
6
7
8
9
10
11

โšก Async Operations

Redux: Thunks with pending/fulfilled/rejected boilerplate

javascript
const fetchTodos = createAsyncThunk("todos/fetch", async (userId) => {
  return fetch(`/api/users/${userId}/todos`).then((r) => r.json())
})

extraReducers: (builder) => {
  builder
    .addCase(fetchTodos.pending, (state) => {
      state.loading = true
    })
    .addCase(fetchTodos.fulfilled, (state, action) => {
      state.data = action.payload
      state.loading = false
    })
    .addCase(fetchTodos.rejected, (state) => {
      state.loading = false
    })
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17

Inglorious Store: Async handlers with full control

javascript
const types = {
  todoList: {
    async fetchTodos(entity, userId, api) {
      entity.loading = true
      const data = await fetch(`/api/users/${userId}/todos`).then((r) =>
        r.json(),
      )
      api.notify("fetchSuccess", data)
    },
    fetchSuccess(entity, data) {
      entity.todos = data
      entity.loading = false
    },
  },
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

๐Ÿ”„ Event System

Redux: Single dispatch, implicit action chains

javascript
// One action dispatched, reducers spread across store
dispatch({ type: "ADD_TODO", payload: "Buy milk" })

// Hard to track what happens next
1
2
3
4

Inglorious Store: Explicit pub/sub with targeted events

javascript
// Broadcast to all handlers
store.notify("taskCompleted", "task123")

// Target specific entity
store.notify("#work:taskCompleted", "task123")

// Target specific type
store.notify("stats:taskCompleted", "task123")
1
2
3
4
5
6
7
8

โ™ป๏ธ Lifecycle

Redux/RTK/Others: No built-in lifecycle

javascript
// Must manually handle setup/cleanup
// No pattern for entity creation/destruction
1
2

Inglorious Store: Built-in lifecycle events

javascript
const types = {
  myType: {
    create(entity) {
      // Automatic on add
      entity.createdAt = Date.now()
    },
    destroy(entity, api) {
      // Automatic on remove
      console.log(`Cleaning up ${entity.id}`)
    },
  },
}

store.notify("add", { id: "entity1", type: "MyType" })
store.notify("remove", "entity1")
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

๐Ÿš€ Performance

LibraryImmutability StrategyRerender Cost
ReduxManual spread operatorsHigh
RTKImmerMedium
ZustandManualVariable
IngloriousMutativeLow

Inglorious Store uses Mutative for 10x faster immutability than Immer:

javascript
entity.value = 100 // Looks like mutation
// Actually immutable under the hood
// 10x faster than Immer
1
2
3

๐Ÿงช Testing

Redux Reducers:

javascript
const state = todosReducer([{ id: 1, text: "Test", done: false }], {
  type: "ADD_TODO",
  payload: "New todo",
})
expect(state[1].text).toBe("New todo")
1
2
3
4
5

Inglorious Store Handlers:

javascript
import { trigger } from "@inglorious/store/test"

const { entity } = trigger(
  { type: "TodoList", todos: [] },
  todoListType.addTodo,
  "New todo",
)
expect(entity.todos[0].text).toBe("New todo")
1
2
3
4
5
6
7
8

Both test easily, but Inglorious provides test utilities.

๐Ÿ’พ DevTools & Debugging

LibraryDevToolsTime TravelInspector
Reduxโœ… Fullโœ… Yesโœ… Yes
RTKโœ… Fullโœ… Yesโœ… Yes
Zustandโš ๏ธ LimitedโŒ Noโš ๏ธ Limited
Jotaiโš ๏ธ LimitedโŒ Noโš ๏ธ Limited
Ingloriousโœ… Fullโœ… Yesโœ… Yes

Inglorious Store provides full Redux DevTools support out of the box.


When to Use Each

Use Redux/RTK if:

  • โœ… You need maximum ecosystem support
  • โœ… You're working on a large team with Redux experience
  • โœ… You want proven battle-tested patterns
  • โŒ You'll benefit from entity-based architecture
  • โŒ You need built-in lifecycle events

Use Inglorious Store if:

  • โœ… You want minimal boilerplate
  • โœ… You manage multiple entity instances
  • โœ… You want integrated async and lifecycle handling
  • โœ… You're starting a new project
  • โœ… You like game engine patterns

Use Zustand/Jotai if:

  • โœ… You want ultra-lightweight state
  • โœ… You don't need Redux DevTools
  • โœ… You're building a small app
  • โŒ You need entity management patterns
  • โŒ You want Redux compatibility

Use Pinia/MobX if:

  • โœ… You're using Vue (Pinia)
  • โœ… You want reactive, observable patterns (MobX)
  • โŒ You need Redux compatibility
  • โŒ You want game engine-inspired patterns

Migration Paths

From Redux โ†’ Inglorious Store

  • Drop-in replacement (same API with react-redux)
  • Keep existing components unchanged
  • Gradually convert slices to types
  • Full guide available: Migrate from Redux

From RTK โ†’ Inglorious Store

  • Convert slices to types
  • Convert thunks to async handlers
  • Migration utilities provided
  • Full guide available: Migrate from Redux

From Zustand/Jotai โ†’ Inglorious Store

  • Rewrite atoms as types
  • Adopt entity-based patterns
  • Gain DevTools and lifecycle benefits

Conclusion

Inglorious Store is the sweet spot for projects that need:

  1. Redux-like predictability and debugging
  2. Minimal boilerplate
  3. Entity management without reshaping state
  4. Built-in lifecycle handling
  5. Native async support

Choose Inglorious Store if you want the simplicity of game engines in your state management.

Released under the MIT License.