Search icon CANCEL
Arrow left icon
Explore Products
Best Sellers
New Releases
Books
Videos
Audiobooks
Learning Hub
Conferences
Free Learning
Arrow right icon
Arrow up icon
GO TO TOP
Micro State Management with React Hooks

You're reading from   Micro State Management with React Hooks Explore custom hooks libraries like Zustand, Jotai, and Valtio to manage global states

Arrow left icon
Product type Paperback
Published in Feb 2022
Publisher Packt
ISBN-13 9781801812375
Length 254 pages
Edition 1st Edition
Languages
Tools
Arrow right icon
Author (1):
Arrow left icon
Daishi Kato Daishi Kato
Author Profile Icon Daishi Kato
Daishi Kato
Arrow right icon
View More author details
Toc

Table of Contents (16) Chapters Close

Preface 1. Part 1: React Hooks and Micro State Management
2. Chapter 1: What Is Micro State Management with React Hooks? FREE CHAPTER 3. Part 2: Basic Approaches to the Global State
4. Chapter 2: Using Local and Global States 5. Chapter 3: Sharing Component State with Context 6. Chapter 4: Sharing Module State with Subscription 7. Chapter 5: Sharing Component State with Context and Subscription 8. Part 3: Library Implementations and Their Uses
9. Chapter 6: Introducing Global State Libraries 10. Chapter 7: Use Case Scenario 1 – Zustand 11. Chapter 8: Use Case Scenario 2 – Jotai 12. Chapter 9: Use Case Scenario 3 – Valtio 13. Chapter 10: Use Case Scenario 4 – React Tracked 14. Chapter 11: Similarities and Differences between Three Global State Libraries 15. Other Books You May Enjoy

Exploring the similarities and differences between useState and useReducer

In this section, we demonstrate some similarities and differences between useState and useReducer.

Implementing useState with useReducer

Implementing useState with useReducer instead is 100% possible. Actually, it's known that useState is implemented with useReducer inside React.

Important Note

This may not hold in the future as useState could be implemented more efficiently.

The following example shows how to implement useState with useReducer:

const useState = (initialState) => {
  const [state, dispatch] = useReducer(
    (prev, action) =>
      typeof action === 'function' ? action(prev) : action,
    initialState
  );
  return [state, dispatch];
};

This can then be simplified and improved upon, as follows:

const reducer = (prev, action) =>
  typeof action === 'function' ? action(prev): prev;
const useState = (initialState) =>
  useReducer(reducer, initialState);

Here, we proved that what you can do with useState can be done with useReducer. So, wherever you have useState, you can just replace it with useReducer.

Implementing useReducer with useState

Now, let's explore if the opposite is possible—can we replace all instances of useReducer with useState? Surprisingly, it's almost true. "Almost" means there are subtle differences. But in general, people expect useReducer to be more flexible than useState, so let's see if useState is flexible enough in reality.

The following example illustrates how to implement the basic capability of useReducer with useState:

const useReducer = (reducer, initialState) => {
  const [state, setState] = useState(initialState);
  const dispatch = (action) =>
    setState(prev => reducer(prev, action));
  return [state, dispatch];
};

In addition to this basic capability, we can implement lazy initialization too. Let's also use useCallback to have a stable dispatch function, as follows:

const useReducer = (reducer, initialArg, init) => {
  const [state, setState] = useState(
    init ? () => init(initialArg) : initialArg,
  );
  const dispatch = useCallback(
    (action) => setState(prev => reducer(prev, action)),
    [reducer]
  );
  return [state, dispatch];
};

This implementation works almost perfectly as a replacement for useReducer. Your use case of useReducer is very likely handled by this implementation.

However, we have two subtle differences. As they are subtle, we don't usually consider them in too much detail. Let's learn about them in the following two subsections to get a deeper understanding.

Using the init function

One difference is that we can define reducer and init outside hooks or components. This is only possible with useReducer and not with useState.

Here is a simple count example:

const init = (count) => ({ count });
const reducer = (prev, delta) => prev + delta;
const ComponentWithUseReducer = ({ initialCount }) => {
  const [state, dispatch] = useReducer(
    reducer,
    initialCount,
    init
  );
  return (
    <div>
      {state}
      <button onClick={() => dispatch(1)}>+1</button>
    </div>
  );
};
const ComponentWithUseState = ({ initialCount }) => {
  const [state, setState] = useState(() => 
    init(initialCount));
  const dispatch = (delta) =>
    setState((prev) => reducer(prev, delta));
  return [state, dispatch];
};

As you can see in ComponentWithUseState, useState requires two inline functions, whereas ComponentWithUseReducer has no inline functions. This is a trivial thing, but some interpreters or compilers can optimize better without inline functions.

Using inline reducers

The inline reducer function can depend on outside variables. This is only possible with useReducer and not with useState. This is a special capability of useReducer.

Important Note

This capability is not usually used and not recommended unless it's really necessary.

Hence, the following code is technically possible:

const useScore = (bonus) =>
  useReducer((prev, delta) => prev + delta + bonus, 0);

This works correctly even when bonus and delta are both updated.

With the useState emulation, this doesn't work correctly. It would use an old bonus value in a previous render. This is because useReducer invokes the reducer function in the render phase.

As noted, this is not typically used, so overall, if we ignore this special behavior, we can say useReducer and useState are basically the same and interchangeable. You could just pick either one, based on your preference or your programming style.

You have been reading a chapter from
Micro State Management with React Hooks
Published in: Feb 2022
Publisher: Packt
ISBN-13: 9781801812375
Register for a free Packt account to unlock a world of extra content!
A free Packt account unlocks extra newsletters, articles, discounted offers, and much more. Start advancing your knowledge today.
Unlock this book and the full library FREE for 7 days
Get unlimited access to 7000+ expert-authored eBooks and videos courses covering every tech area you can think of
Renews at €18.99/month. Cancel anytime