Skip to content

Uses of different react state management tools: useState, Context, Recoil, Redux and MobX.

Notifications You must be signed in to change notification settings

anushkachauhxn/react-state-management

Folders and files

NameName
Last commit message
Last commit date

Latest commit

Β 

History

5 Commits
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

πŸͺ React: State Management

Switch between different branches to see usage examples.

Contents:

  1. useState Hook
  2. Context API
  3. Recoil
  4. Redux
  5. MobX

🍧 1. useState

import { useState } from "react";
const [value, setValue] = useState(0); // default value

handleChange = () => {
  setValue(value + 1); // takes a function that returns new value
};

πŸ’ 2. Context API

  • Allows components to share state without having to pass the data as props all the time.
  • Helps avoid props drilling.

Creating Context

const CounterContext = createContext();

Creating Custom Provider

const CounterProvider = ({ children }) => {
  const [numberOfClicks, setNumberOfClicks] = useState(0);

  const increment = (amount) => {
    setNumberOfClicks(numberOfClicks + amount);
  };

  return (
    <CounterContext.Provider value={{ numberOfClicks, increment }}>
      {children}
    </CounterContext.Provider>
  );
};

Using Context

  • Wrap the necessary components in the provider.
<CounterProvider>
  <div className="app">...</div>
</CounterProvider>
  • Then, access the data in any of those components using useContext hook.
const { numberOfClicks, increment } = useContext(CounterContext);

πŸ₯‘ 3. Recoil State Management

Recoil has two main concepts: atoms and selectors.

  • Atoms are individual values that we want to store in the Recoil state.
  • Selectors take the fundamental values expressed as atoms and transform them in some way or combine them into another value.

Note: All the components within recoil will share this state. It is useful in many scenarios but could be problematic in others.

npm install recoil

Creating Recoil State

  • Atoms are functions that we can use to create new pieces of the Recoil state.
const counterState = atom({
  key: "counterState",
  default: 0,
});

Using Recoil State

Wrap the components in <RecoilRoot> and then access the state in any of those components using:

  • useRecoilValue hook: to access a particular state value.
const numberOfClicks = useRecoilValue(counterState);
  • useRecoilState hook: to access and modify a particular state value.
const [numberOfClicks, setNumberOfClicks] = useRecoilState(counterState);

Using Selectors

Selectors allow us to define certain logic in one spot. Instead of defining the logic in multiple components, we can use a selector instead.

const numberOfClicksSelector = selector({
  key: "numberOfClicksSelector",
  get: ({ get }) => {
    // get currrent data from a recoil state
    const clicksData = get(counterState);

    // return a modified value
    const numberOfClicks = clicksData.reduce((sum, clickData) => {
      return sum + clickData.amount;
    }, 0);
    return numberOfClicks;
  },
});

Access the modified value in any of those components using useRecoilValue hook.

πŸ‰ 4. Redux State Management

npm install redux react-redux

1. Actions

  • Any action that can potentially change the state of our application.
  • Eg: when user clicks on a button, when data finishes loading, when data starts loading.
  • It contains: type of action and payload
export const counterButtonClicked = {
  type: "COUNTER_BUTTON_CLICKED",
  payload: { amount: 1 },
};

Action Creators

  • An action creator is a function that takes in any values and returns an action according to said values.
export const counterButtonClicked = (amount) => ({
  type: "COUNTER_BUTTON_CLICKED",
  payload: { amount: amount },
});

2. Reducers

  • Reducers tell redux how the state of our application should change whenever any given action occurs.
  • Takes in: current state and action.
  • Returns: new state after action.
export const numberOfClicksReducer = (state = 0, action) => {
  const { type } = action;

  switch (type) {
    case "COUNTER_BUTTON_CLICKED":
      return state + action.payload.amount;
    default:
      return state;
  }
};
  • It generally involves a switch function for type of action involved.
  • Default case returns state as it is, i.e. no change.

3. Selectors

  • Allow components to accurately get data out of the state and occasionally to transform data of the state.
export const numberOfClicksSelector = (state) => state.numberOfClicks;

=> Using Redux

i. Create a store

  • Combine reducers using combineReducers and create a redux store using the rootReducer.
const rootReducer = combineReducers({
  numberOfClicks: numberOfClicksReducer,
});

const store = createStore(rootReducer);

ii. Use selectors

  • Get values from state using useSelector hook with the corresponding selector.
const numberOfClicks = useSelector(numberOfClicksSelector);

iii. Dispatch actions

  • Tell redux that an action should get dispatched using useDispatch hook with the corresponding action.
const dispatch = useDispatch();

...

<button onClick={() => dispatch(counterButtonClicked)}>Click Me</button>

πŸ‡ 5. MobX State Management

MobX takes a more object-oriented approach as compared to redux.

npm install mobx mobx-react-lite

Creating MobX State

  • Use a class to store the state.
  • The class can contain values and actions.
class Counter {
  value = 0;

  constructor() {
    makeObservable(this, {
      value: observable,
      increment: action,
    });
  }

  increment = (amount) => {
    this.value += amount;
  };
}

Using MobX State

  • Pass an instance of that class to components.
const counter = new Counter();
<DisplayCount counter={counter} />
<CounterButton counter={counter} />

Important: Do not forget

  • use makeObservable or makeAutoObservable in the class constructor
constructor() {
  makeObservable(this, {
    value: observable,
    increment: action,
  });
}

or

constructor() {
  makeAutoObservable(this)
}
  • wrap your components in observer
const CounterButton = observer(({ counter }) => {
  ...
});

Note:

Since we are passing the class instance to components through props, it can again result in props drilling.

We can use Context API with MobX to make the class instance available to all components.

About

Uses of different react state management tools: useState, Context, Recoil, Redux and MobX.

Topics

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published