Written by Dave Ceddia

Click “like” and then look, wechat search [Big Move the world] pay attention to this person without dACHang background, but with a positive attitude upward. In this paper, making github.com/qq449245884… Has been included, the article has been categorized, also organized a lot of my documentation, and tutorial materials.

Everyone said there was no project on your resume, so I found one and gave it away【 Construction tutorial 】.

Look at the word “Reducer” and it’s easy to think of Redux, but in this article you don’t need to understand Redux to read this article. Let’s discuss what “Reducer” really is, how to use useReducer to manage complex state in components, and what this new hook means for Redux.

What is Reducer

If you are familiar with the Reduce methods on Redux or arrays, you probably know what “Reducer” is. If you’re not familiar with this, “Reducer” means a function with two values that returns one.

If you have a series of things and you want to combine them into a single object. Functional programming is the use of Array’s Reduce function. For example, if you have an array of numbers and want the sum of all the numbers in the array, we can write a reducer function and pass it to Reduce, as follows:

let numbers = [1, 2, 3]; let sum = numbers.reduce((total, number) => { return total + number; }, 0)Copy the code

If you haven’t used this before, it might seem a little mysterious. All it does is call a function for each element of the array, passing in the previous total and the current element number. Whatever you return will become the new total. The second argument to reduce (0 in this case) is the initial value of total. In this case, the reduce function is called three times:

  • call(0, 1)return1
  • call(1, 2)return3
  • call(3, 4)return6

Reduce returns 6, which is stored in sum.

What about using useReducer?

You have spent half the space explaining Array’s Reduce function because useReducer has the same parameters as Reduce and works in much the same way. The useReducer receives (state, action) => newState and returns a dispatch method paired with the current state. Let’s use useReducer to write the above summation example.

useReducer((state, acton) => {
  return state + action
}, 0)
Copy the code

UseReducer returns an array of two elements, similar to useState Hook. The first is the current state and the second is the Dispatch method, as shown below:

const [sum, dispatch] = useReducer((state, action) => {
  return state + action
}, 0)
Copy the code

Note that state can be any value, it doesn’t have to be an object, it can be a number, an array, or any other type.

Although useReducer is an extended hook and useState is the basic hook, useState actually implements a useReducer as well. This means that useReducer is more native and you can replace it with useReducer wherever you use useState.

import React, { useReducer } from 'react';

function Counter() {
  // First render will create the state, and it will
  // persist through future renders
  const [sum, dispatch] = useReducer((state, action) => {
    return state + action;
  }, 0);

  return (
    <>
      {sum}

      <button onClick={() => dispatch(1)}>
        Add 1
      </button>
    </>
  );
}
Copy the code

Click the button to dispatch an action with a value of 1, which is added to the current state, and the component is then re-rendered with the new state.

It is deliberately shown here that distributing actions does not follow the typical Redux pattern {type: “INCREMENT BY”, value: 1}, or anything like that. The world of hooks is a new world: it’s worth considering whether you find old patterns valuable and want to keep them, or whether you’re willing to change them.

Some more complicated examples

Let’s look at an example that is closer to a typical Redux Reducer. Create a component to manage the shopping list, using another hook here :useRef.

First, import two hooks

import React, { useReducer, useRef } from 'react';
Copy the code

Then create a component that sets the ref and Reducer. Ref saves a reference to the form so we can extract its value.

function ShoppingList() {
  const inputRef = useRef();
  const [items, dispatch] = useReducer((state, action) => {
    switch (action.type) {
      // do something with the action
    }
  }, []);

  return (
    <>
      <form onSubmit={handleSubmit}>
        <input ref={inputRef} />
      </form>
      <ul>
        {items.map((item, index) => (
          <li key={item.id}>
            {item.name}
          </li>
        ))}
      </ul>
    </>
  );
}
Copy the code

Note that in this case, our “state” is an array. We initialize it as an empty array with the second parameter of the useReducer and return an array from the Reducer function.

useRef Hook

The useRef hook creates persistent references to DOM nodes. Calling useRef creates an empty node. The object it returns has a current property, so in the example above, we can use inputref.current to access the input DOM node. If you’re familiar with react.createref (), it works very similarly.

However, the object returned by useRef is more than just a way to hold a DOM reference. It can hold any value specific to this component instance, and it remains constant from rendering to rendering.

UseRef can be used to create generic instance variables, as with the React class component with this.whatever = value. The only problem is that writing it is considered a “side effect”, so we can’t change it during rendering, we need to change it in useEffect Hook.

Back to the useReducer example

We use forms to process user input and press Enter to submit recognition. Now write the handleSubmit function, which adds an item to the list and handles the actions from the Reducer.

function ShoppingList() { const inputRef = useRef(); const [items, dispatch] = useReducer((state, action) => { switch (action.type) { case 'add': return [ ...state, { id: state.length, name: action.name } ]; default: return state; }} []); function handleSubmit(e) { e.preventDefault(); dispatch({ type: 'add', name: inputRef.current.value }); inputRef.current.value = ''; } return ( // ... same ... ) ; }Copy the code

The Reducer function mainly determines two cases: one case when action.type===’add’ and the default case.

When action.type is add, it returns a new array containing all the old elements, as well as the last new element.

One thing to note here is that using array length as an auto-incrementing ID is easy to demonstrate, but unreliable for a real application because it can lead to duplicate ids and bugs. (Better to use a library like uUID, or have the server generate a unique ID!)

The handleSubmit function is called when the user presses Enter in the input box, so we need to call preventDefault to avoid reloading the entire page if this happens. Dispatch then dispatches an action.

Delete the item

Now let’s see how to remove items from the list.

Add a delete

Then we just need to work on the action in the Reducer

function ShoppingList() {
  const inputRef = useRef();
  const [items, dispatch] = useReducer((state, action) => {
    switch (action.type) {
      case 'add':
        // ... same as before ...
      case 'remove':
        // keep every item except the one we want to remove
        return state.filter((_, index) => index != action.index);
      default:
        return state;
    }
  }, []);

  function handleSubmit(e) { /*...*/ }

  return (
    <>
      <form onSubmit={handleSubmit}>
        <input ref={inputRef} />
      </form>
      <ul>
        {items.map((item, index) => (
          <li key={item.id}>
            {item.name}
            <button
              onClick={() => dispatch({ type: 'remove', index })}
            >
              X
            </button>
          </li>
        ))}
      </ul>
    </>
  );
}
Copy the code

Exercise: Clear the list

Try adding a feature: add a button to clear the list.

Insert a button above

    , provide it with an onClick prop, distribute an action of type “clear”, and clear the list in the Reducer method.

This can be done based on the previous CodeSandbox.

Die Redux

Most people see useReducer hook, React now has built-in reducer, it has Context to pass data, so they may think that Redux will die because of this.

The author does not believe that useReducer will kill Redux. React Hook extends React’s state management capabilities, so Redux will be used less often.

Redux still does more than the Context + useReducer combination. It has Redux DevTools for debugging, customizable middleware, and the entire library ecosystem. Of course, Redu X is overused in many places, but it’s still powerful.

Redux provides a global store in which application data can be stored centrally. The useReducer is localized to a specific component. However, there is nothing to stop us from building our own mini Redux using useReducer and useContext. If you want to do it and it fits your needs, go for it!

The bugs that may exist after code deployment cannot be known in real time. In order to solve these bugs, I spent a lot of time on log debugging. Incidentally, I recommend a good BUG monitoring tool for youFundebug.

The original:

www.robinwieruch.de/react-usere…

communication

This article is updated every week, you can search wechat “big move the world” for the first time to read and urge more (one or two earlier than the blog hey), this article GitHub github.com/qq449245884… It has been included and sorted out a lot of my documents. Welcome Star and perfect. You can refer to the examination points for review in the interview.