На этот раз завершите useReducer — основные понятия

React.js
На этот раз завершите useReducer — основные понятия

useReducer-Основные понятия

useReducer-использовать статьи

useReducer — используется с useContext

useReducerЭто продвинутый хук, предоставляемый React. Это не то же самое, что useEffect, useState, useRef и другие необходимые хуки. Без него мы можем нормально завершить разработку требований, но useReducer может сделать наш код более читабельным и ремонтопригодным. , предсказуемость .

Ниже мы будем разделены на три статьи с подробным описанием того, как использовать его в проекте.useReducer:

  • Часть 1. Основное введение в JavaScriptreducerПонятие и его характеристики, друзья, знакомые с редюсером, редуксом и т.п., могут пропустить эту статью
  • Часть 2: Основное введениеuseReducerКак его использовать и его сценарии, а также преимущества useReducer
  • Третья часть: дальнейшее введение в использование useReducer в сложных проектах и ​​сложных страницах.

что такое редуктор

reducerЭта концепция постепенно становится популярной в JavaScript с появлением Redux. Но нам не нужно изучать Redux, чтобы понять Reducer. Проще говоря, редуктор — это функция(state, action) => newState: получение состояния текущего приложения и инициированного действия, вычисление и возврат последнего состояния. Вот кусок псевдокода:

    // 举个栗子 计算器reducer,根据state(当前状态)和action(触发的动作加、减)参数,计算返回newState
    function countReducer(state, action) {
        switch(action.type) {
            case 'add':
                return state + 1;
            case 'sub':
                return state - 1;
            default: 
                return state;
        }
    }

Приведенный выше пример: состояние является значением типа number, редюсер изменяет состояние в соответствии с типом действия (сложение, вычитание) и возвращает конечное состояние. просто для связиreducerКонцепцию легче понять, вы можете изменить состояние для подсчета, но всегда помните, что подсчет по-прежнемуstate.

    function countReducer(count, action) {
        switch(action.type) {
            case 'add':
                return count + 1;
            case 'sub':
                return count - 1;
            default: 
                return count;
        }
    }

Идемпотентность редукторов

Как видно из примера вышеreducerПо сути, чистая функция без какого-либо пользовательского интерфейса и побочных эффектов. Это означает, что при одних и тех же входных данных (состоянии, действии) функция-редуктор всегда будет возвращать один и тот же результат (newState), независимо от того, сколько раз она выполняется. Следовательно, с помощью функции редуктора легко вывести изменения состояния, а также проще выполнить модульное тестирование.

    expect(countReducer(1, { type: 'add' })).equal(2); // 成功
    expect(countReducer(1, { type: 'add' })).equal(2); // 成功
    expect(countReducer(1, { type: 'sub' })).equal(0); // 成功

Понимание состояния и нового состояния

stateЭто текущий объект состояния приложения, который можно понимать как состояние в React, с которым мы знакомы.

В приведенном выше примере состояние является базовым типом данных, но во многих случаях состояние может быть сложным объектом JavaScript, например, количество в приведенном выше примере может быть просто свойством в состоянии. Для этого сценария мы можем использовать назначение структуры ES6:

    // 返回一个 newState (newObject)
    function countReducer(state, action) {
        switch(action.type) {
            case 'add':
                return { ...state, count: state.count + 1; }
            case 'sub':
                return { ...state, count: state.count - 1; }
            default: 
                return count;
        }
    }

Есть два важных момента, которые следует помнить о приведенном выше коде:

  1. Объект состояния, обрабатываемый редуктором, должен бытьimmutable, что означает, что никогда не изменяйте напрямую объект состояния в параметре, функция редуктора должна каждый раз возвращать новый объект состояния.

  2. Поскольку редюсер должен каждый раз возвращать новый объект, мы можем использовать ES6.присваивание деструктуризацииЧтобы создать новый объект и переопределить свойство состояния, нам нужно изменить его, как в примере выше.

Это выглядит идеально, но если наше состояние вложено в несколько слоев, реализация присваивания деструктуризации будет очень сложной:

    function bookReducer(state, action) {
        switch(action.type) {
            // 添加一本书
            case 'addBook':
                return {
                    ...state,
                    books: {
                        ...state.books,
                        [bookId]: book,
                    }
                };
            case 'sub':
                // ....
            default: 
                return state;
        }
    }

Рекомендуется для таких сложных сценариев состоянияimmerВ ожидании решить неизменной библиотеку.

Почему состояние должно быть неизменяемым?

  • Идемпотентность редукторов

Выше мы упоминали, что редукторы должны оставаться идемпотентными, более предсказуемыми и проверяемыми. Если каждый раз возвращается одно и то же состояние, нет гарантии, что результат будет одинаковым независимо от того, сколько раз оно выполняется.

  • Схема сравнения состояний в React

React сравниваетoldStateа такжеnewStateИменно при использовании функции Object.is, если это один и тот же объект, ретрендер компонента не улетит. Можно сослаться на официальный документbailing-out-of-a-dispatch.

понимание действия

действие: используется для представления инициированного поведения.

  1. Используйте тип для представления определенного типа поведения (вход в систему, выход из системы, добавление пользователя, удаление пользователя и т. д.).
  2. Используя данные, переносимые полезной нагрузкой (например, добавление книг, вы можете передавать определенную информацию о книгах), давайте в качестве примера возьмем действие addBook выше:
    const action = {
        type: 'addBook',
        payload: {
            book: {
                bookId,
                bookName,
                author,
            }
        }
    }
    function bookReducer(state, action) {
        switch(action.type) {
            // 添加一本书
            case 'addBook':
                const { book } = action.payload;
                return {
                    ...state,
                    books: {
                        ...state.books,
                        [book.bookId]: book,
                    }
                };
            case 'sub':
                // ....
            default: 
                return state;
        }
    }

Суммировать

На данный момент основное введение в контент, связанный с редуктором, завершено, и краткое резюме:reducerэто использованиеactionПредоставленная информация будетstateЧистая функция, которая преобразует из A в B, имеет следующие характеристики:

  • Синтаксис: (состояние, действие) => новое состояние
  • Неизменяемый: возвращайте newState каждый раз, никогда не изменяйте объект состояния напрямую
  • Действие: обычный объект Action обычно состоит из типа и полезной нагрузки (необязательно).
    • тип: Тип этой операции, который также является основой для условного суждения редуктора.
    • Полезная нагрузка: Предоставляет данные, прикрепленные к операции.

В следующей статье мы перейдем к сути: как использовать useReducer для упрощения управления нашим состоянием.

Последняя практика, приветствуем всех, чтобы отметить нашуБлог фронтенд-команды Renrendai, все статьи также будут обновляться синхронно сЗнай колонкуа такжеСчет наггетс, мы еженедельно делимся несколькими высококачественными техническими статьями о внешнем интерфейсе. Если вам понравилась эта статья, я надеюсь, что вы можете поставить палец вверх.

использованная литература