DEV Community

Slava Yefremov
Slava Yefremov

Posted on

Redux Toolkit == MobX?

I don't like Redux because of its complexity and dozens of lines of boilerplate code. So, I've never used it in production. When I worked on existing Redux-projects that someone left to me (you know, these aren't perfect projects 🤪), I always replaced Redux with MobX, and the code became clearer at times.

But today I tried Redux Toolkit, an official toolset for efficient Redux development, and now I want to try it in production. In this post, I'm going to compare MobX and Redux Toolkit in terms of their simplicity. I'm not a Redux-guy, so feel free to point out my mistakes, if any.

Ok, here we go!

I won't show you a gradual transition from "Vanilla Redux" to Redux Toolkit, because you can find it in the docs. I just show you a simple "slice" (the equivalent of MobX store) with a counter.

export const counterSilce = createSlice({
  name: 'counter',
  initialState: 0,

  reducers: {
    increment: (state) => state + 1,
    decrement: (state) => state - 1,
  },
})

export const store = configureStore({
  reducer: counterSilce.reducer,
})
Enter fullscreen mode Exit fullscreen mode

You may ask, "What? Where is my ugly favorite action creators? Is it Redux?" At least I had just such questions a couple of hours ago.

But how can you use it?
It's simple, just like a regular store.

const Component = () => {
  const dispatch = useDispatch()

  const counter = useSelector((counter) => counter)

  return (
    <section>
      <button onClick={() => dispatch(counterSilce.actions.decrement())}>
        -
      </button>

      <span>{counter}</span>

      <button onClick={() => dispatch(counterSilce.actions.increment())}>
        +
      </button>
    </section>
  )
}
Enter fullscreen mode Exit fullscreen mode

And now look at the MobX store. Very similar, isn't it?

// MobX store
export const counterStore = () => ({
  counter: 0,

  increment() {
    this.counter += 1
  },

  decrement() {
    this.counter -= 1
  },
})
Enter fullscreen mode Exit fullscreen mode

Fetching data

Now I'll show you a little more complex example: fetching data. I'll use JSONPlaceholder API to fetch a list of users with Redux Toolkit.

Firstly, let me configure the slice. I'll store the loading flag and array of users in the state (error handling omitted for simplicity).

export const usersSlice = createSlice({
  name: 'users',
  initialState: {
    loading: false,
    users: [],
  },

  reducers: {},
})
Enter fullscreen mode Exit fullscreen mode

Here will be two reducers: one for setting loading to true (before fetching) and second for updating users (after fetching).

export const usersSlice = createSlice({
    // ...

  reducers: {
    getUsersStart: (state) => ({ ...state, loading: true }),

    getUsersSuccess: (state, action) => ({
      ...state,
      loading: false,
      users: action.payload.users.map((u) => ({
        id: u.id,
        name: u.name,
        username: u.username,
      })),
    }),
  },
})
Enter fullscreen mode Exit fullscreen mode

And I'll use an action creator which returns a function with dispatch for the request itself.

const fetchUsers = () => (dispatch) => {/* ... */}
Enter fullscreen mode Exit fullscreen mode

But wait, we need a thunk middleware for this, right? Indeed. But Redux Toolkit took care of that by including some middleware by default, so we don't need to install it manually.

The logic of the fetching function is simple: enable loading, make HTTP request, disable loading, update users array.

export const fetchUsers = () => (dispatch) => {
  try {
        // enable 'loading'
    dispatch(usersSlice.actions.getUsersStart())

        // make HTTP request
    fetch('https://jsonplaceholder.typicode.com/users')
      .then((r) => r.json())
      .then((users) => {
                // disable 'loading', update 'users' array
        dispatch(usersSlice.actions.getUsersSuccess({ users }))
      })
  } catch (error) {
    console.error(error)
  }
}
Enter fullscreen mode Exit fullscreen mode

And finally, we need to connect all this logic to React.

const Component = () => {
  const dispatch = useDispatch()

  const usersStore = useSelector((store: Store) => store)

  useEffect(() => {
    dispatch(fetchUsers())
  }, [])

  return (
    <main>
      {usersStore.loading ? (
        <span>Loading...</span>
      ) : (
        usersStore.users.map((u) => (
          <div key={u.id}>
            <span>{u.name}</span>
            <span>{u.username}</span>
          </div>
        ))
      )}
    </main>
  )
}
Enter fullscreen mode Exit fullscreen mode

You can find all these examples in my GitHub repo.

Yeah, Redux Toolkit is an amazing tool for Redux. Just try it and share your impressions.

Top comments (1)

Collapse
 
khavnguyen profile image
Kha Nguyen

Hey Viacheslav, great article.
I've been trying to decide between MobX vs Redux Toolkit for my upcoming project. I'd say I'm comfortable with both and they end up being kind of similar. Based on your experience with both, which would you prefer these days?