Skip to content

Instantly share code, notes, and snippets.

@staydecent
Last active May 22, 2020 18:35
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save staydecent/1de659d86696bced372cb456730f038a to your computer and use it in GitHub Desktop.
Save staydecent/1de659d86696bced372cb456730f038a to your computer and use it in GitHub Desktop.
atom/redux concepts and best practices

atom Concepts

At Input Logic, we use atom to manange state in our React apps. atom is modeled after Redux, which is a pattern for state management that has stood up in countless apps over the years. This is a succinct overview of the atom/redux concepts and best practices we employ.

What is Redux?

The three principles are the foundation of Redux. Briefly:

  1. Your application (or shared) state is stored in a single object.
  2. The application state object is immutable. You cannot just globalState.someValue = 4 as the application state object is not directly accessible.
  3. Changes are made with pure functions. You define actions and reducers to describe and handle changes to your application state.

The first two prinicples are rather self-explanatory, but actions and reducers are a new concept. To change your state object, you need to dispatch an action.

An action can be just a string, or an object or any value you want. However, we enforce using Flux Standard Actions. So, an action is an object that describes a state change.

store.dispatch({ type: 'INCREMENT' })

To handle those state change descriptions, we define reducers. A reducer is a function that accepts function (action, state) and returns the potentially modified state. There is no limit to the number of reducers you define. When an action is dispatched, atom will call each defined reducer, in the given order. Each subsequent reducer receives the potentially modified state from the previous reducer.

// atom accepts a single reducer or an array.
// `0` is our initial state.
const store = atom(counter, 0)

function counter (action, state) {
  switch (action.type) {
    case 'INCREMENT':
      return state + 1
    case 'DECREMENT':
      return state - 1
    default:
      return state
  }
}

Why Redux over a more basic Global Store?

Why not just have a single object that can be mutated? Why not just have a setState function on a global store, instead of creating actions and reducers? I've written about this in detail, but briefly:

  1. actions and reducers allow traceable state changes.
  2. Refactoring is much easier.

Should I use global state or useState?

Not sure when to use useState in your React component versus global state? We follow this pretty basic rule:

If your data is shared in more than one Component, store it in global state.

Why atom over Redux?

I actually found Redux could be made even simpler. Some concepts are removed, and some conveniences are added:

  1. Redux supports a single Reducer, providing a combineReducers function to help break apart your reducer logic. atom accepts an array of reducers, and actually reduces them.
  2. Because atom supports an array of reducers, it provides the addReducer and removeReducer functions instead of Redux's replaceReducer.
  3. atom does not implement middleware. Middleware is considered dangerous. It can interfere with traceability and can very easily complicate code. Instead, atom has a very primitive listener api, and thunks are built in.
  4. atom comes with setState, utilizing an internal reducer that will merge the passed in state with the existing state, for faster prototyping.

How should I organize my global state?

To keep the global state object manageable, we recommend limiting the amount of nested objects and arrays. Generally, you don't want to nest more than 1 level deep on the global state object.

// bad 👎
{
  blog: {
    posts: []
  }
}

// good 👍
{
  blogPosts: []
}

Use Action Creators

TODO

Thunks, or async actions

TODO

Wrapping Up

Hopefully, that covers everything you need to know about atom/redux and global state. If you have any questions, please reach out!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment