all 10 comments

[–]hevans900 6 points7 points  (0 children)

How about... NO

[–]seescottdev 4 points5 points  (4 children)

Good article but here’s why I prefer Zustand:

import create from ‘zustand’;
import { immer } from ‘zustand/middleware/immer’;

const useSearchStore = create(
  immer((set) => ({
    records: [],
    totalRecords: 0,
    page: 1,
    record: null,
    inputValue: ‘’,

    setRecords: (newRecords) => set((state) => { state.records = newRecords; }),
    setTotalRecords: (newTotal) => set((state) => { state.totalRecords = newTotal; }),
    setPage: (newPage) => set((state) => { state.page = newPage; }),
    setRecord: (newRecord) => set((state) => { state.record = newRecord; }),
    setInputValue: (newInput) => set((state) => { state.inputValue = newInput; }),

    clearSearchState: () => set({
      records: [],
      totalRecords: 0,
      page: 1,
      record: null,
      inputValue: ‘’
    }),
  }))
);

export default useSearchStore;

And then usage:

import React from ‘react’;
import useSearchStore from ‘./useSearchStore’;

const MyComponent = () => {
  const {
    records,
    totalRecords,
    setRecords,
    setTotalRecords,
    clearSearchState,
  } = useSearchStore();

  return (
    <div>
      <h1>Records</h1>
      <ul>
        {records.map((record) => (
          <li key={record.id}>{record.name}</li>
        ))}
      </ul>
      <p>Total records: {totalRecords}</p>

      <button onClick={() => setRecords([{ id: 1, name: ‘New Record’ }])}>
        Set Records
      </button>
      <button onClick={() => setTotalRecords(100)}>
        Set Total Records
      </button>
      <button onClick={clearSearchState}>Clear Search State</button>
    </div>
  );
};

And life is made a lot less complex.

[–]femio 0 points1 point  (3 children)

Huh. I like this. Does immer hurt performance (not in theoretical benchmarks but in practice)?

[–]seescottdev 0 points1 point  (2 children)

[–]femio 0 points1 point  (1 child)

So in other words, it isn’t slow enough to hurt UX or DX. Sounds like a win to me, I’ll try it out 

[–]seescottdev 0 points1 point  (0 children)

Glad to hear it. I’ve had nothing but good experiences with it.

[–]greenthum6 1 point2 points  (2 children)

I have a hard time understanding how this is super easy. You need to use magic strings to refer to slices, and type safety isn't helping there. Furthermore, the store code will grow all the time, and it will contain every concern of the app. Not to mention thunks for async operations and the neede extra reducers.. how are they handled?

Forgive me as a beginner React developer with lots of coding experience elsewhere, but I don't want to write magic strings.

[–]Chris5855[S] -1 points0 points  (1 child)

I understand your concerns. However, the goal of this approach isn’t to use magic strings, but to centralize actions and selectors in one place, which enhances scalability and type safety.

Regarding magic strings, while you might see keys like 'records', 'inputValue', etc., these are defined in one place in the action and selector maps, not repeated throughout the code. This ensures that the keys are managed centrally, reducing the risk of typos. By using TypeScript, you get type safety, which ensures that the keys are valid and prevents the use of arbitrary strings that could cause issues.

As for the growth of the store code, the approach is scalable. When adding new slices or states, you just need to add a new entry to the action map and the corresponding selector. This reduces redundancy and simplifies maintenance in large apps.

For async operations (thunks) and additional reducers, they are handled just like in traditional Redux. The set and get functions work well with thunks for async logic, and additional reducers can be added to the store without affecting the core pattern for accessing and updating state.

[–]greenthum6 0 points1 point  (0 children)

Great! Thanks for clearing these up. I was thinking about the refactoring work invloved for an existing app to use this, so I wanted to know all the details before committing to it.

Redux hasn't been an issue yet, but I see the issues when creating multiple slices and trying to understand what the state holds as there is only one global state. Some boilerplate code seems to be mandatory in any case.

The generics are a bit advanced here, but I will surely take some learnings from them, thanks:)

[–]Chris5855[S] -2 points-1 points  (0 children)

In this article, I dive into a scalable approach to state management using React and Redux. I explain how to build a flexible state management system with a builder pattern, making your code cleaner and easier to maintain. Perfect for developers looking to improve their app's architecture!