loading...
Cover image for Beginner's guide to React State

Beginner's guide to React State

petr7555 profile image Petr Janik Updated on ・4 min read

React (3 Part Series)

1) Export / Import components in React 2) Classes vs Functional components in React 3) Beginner's guide to React State

Background

I have started learning React two months ago. At that time, I was overwhelmed by all the different possibilities of React. I have addressed two of them already in the previous aticles of this series. The remaining one - state management - will be discussed in this article.
Throughout my learning, these examples have proven priceless to me as I always had some React sandbox to play and experiment with. They served as a reminder of what I already learnt. I hope they will be of use to you as well.

How this works

I have implemented a simple TODO app in every state management way I came across. The functionality is pretty basic. You can list existing todos and add a new todo.
It uses a backend running on heroku. https://todo-backend-rest.herokuapp.com/todos/ for REST API and https://todo-backend-graphql.herokuapp.com/ for GraphQL API.
The code is on codesandbox.io so you can easily run it or fork it and edit.

Table Of Contents

State in class components

We create a class component and use its state property and setState method.

useState hook + useThunkReducer

Earlier, when we wanted to manage state, we had to use a class component.
This is no longer the case with the arrival of hooks.
This sandbox contains two approaches. The first one is useState hook and the second one would be useReducer. However, I had to use useThunkReducer from react-hook-thunk-reducer instead of built-in useReducer to dispatch async actions that are needed for fetching. This is an alternative of Redux and redux-thunk.

Redux

This approach has proven to be the most verbose one.
Witing Redux with typescript's type checking is even more boilerplate code.
Redux needs another helper library for side effects (fetching etc.) such as redux-thunk or redux-saga.
This sandbox contains:

  • an older approach using mapStateToProps and mapDispatchToProps connected with react-redux connect HOC function
  • a newer approach using useSelector and useDispatch hooks

MobX class component

Mobx is used for state management (both local and global) and for observing.
This sandbox contains:

  • an older approach using class stores and @inject and @observer annotations.
  • class component using inject and observer HOC
  • functional component using inject and observer HOC The store is provided via Provider component from mobx-react.
<Provider {...store}>
  <TodoList/>
</Provider>

This approach is deprecated and the following ones taking advantage of React Context should be used.

MobX and context (not null)

Here we take advantage of custom useStores hook.

const {TodoStore} = useStores();

The useStores hook consumes storesContext via useContext hook.
storesContext is initialized to { TodoStore: new TodoStore() } so we do not need to provide the context in <storesContext.Provider> component.

MobX and context (null)

If we didn't want to create context with initial value as in previous approach, we could create a custom <StoreProvider> component. This component returns a <storesContext.Provider>.
The useStores hook now also checks, whether the store (i. e. the value of context) is not null.
This sandbox also contains 4 ways of observing the state:

  • observer HOC with regular function
  • observer HOC with arrow function
  • <Observer> component
  • useObserver hook

MobX and useLocalStore

We have seen useLocalStore hook used in the MobX and context (null).
From the MobX documentation:

The naming useLocalStore was chosen to indicate that store is created locally in the component. However, that doesn't mean you cannot pass such store around the component tree. In fact it's totally possible to tackle global state management with useLocalStore despite the naming. You can for example setup bunch of local stores, assemble them in one root object and pass it around the app with a help of the React Context.

Which is exacty what we did in the previous example.
In this example, however, we insert the code of the store directly into the component.

React plain Context

We can create a global state in App component and then pass it to other components by using React Context.

Apollo GraphQL

Here, we use Apollo's useQuery and useMutation hooks.

React Query

useQuery and useMutation hooks with caching, optimistic updates and automatic refetching.
This and many more features are available with React Query.

So which one should you choose?

First thing to note is that those ways are not mutually exclusive, you can make use of both Redux and GraphQL at the same time.
I'd say that Redux is a lot of fun and provides a nice way of debugging when using redux-devtools-extension. However, the code overhead is huge, especially when combined with TypeScript. For smaller projects, I would choose MobX instead or even plain React Context.

This article (from 2016) discusses the advantages and drawbacks of Redux.

P.S. I've heard React Recoil is going to be the next big thing.

Resources:

Mobx docs
React Redux docs
React docs
Cover photo by v2osk on Unsplash.

React (3 Part Series)

1) Export / Import components in React 2) Classes vs Functional components in React 3) Beginner's guide to React State

Posted on Jun 1 by:

petr7555 profile

Petr Janik

@petr7555

I'm a student of applied informatics at Masaryk University in Brno. I love coding, especially in Java and Python.

Discussion

markdown guide