Встреча по пакету обучения Redux (1): знакомство с тремя основными концепциями Redux

React.js
Встреча по пакету обучения Redux (1): знакомство с тремя основными концепциями Redux

Управление состоянием интерфейсных приложений становится все более сложным. С наступлением эпохи большого фронтенда фронтенд все больше внимания уделяет логике обработки, а не просто фокусируется на улучшении уровня пользовательского интерфейса.Появление фронтенд-фреймворков в лице React значительно упростило сложность написания UI интерфейсов. Хотя React предоставляет механизм состояния для управления состоянием, а также соглашения о разработке, такие как «продвижение состояния», эти решения подходят только для небольших приложений.Когда ваше внешнее приложение имеет более 10 страниц, как сделать состояние приложения управляемым , Сделать совместную разработку эффективной стало насущной проблемой, и Redux был создан для решения этих проблем! «Единый источник достоверных данных», односторонний поток данных и «чистые редукторы функций», предложенные Redux, значительно упрощают интерфейсную логику, позволяя нам писать произвольно сложные интерфейсные приложения эффективным и совместным образом. Это руководство посвящено объяснению Redux в коротких текстах и ​​пониманию концепций и сути Redux на практике.

Добро пожаловать в серию обучающих пакетов Redux:

Этот учебник принадлежитМаршрут обучения фронтенд-инженера ReactЧасть , добро пожаловать в звездную волну, поощряйте нас продолжать создавать лучшие учебные пособия и продолжать обновлять ~.

прежде чем мы прочитаем учебник

Официальная документация Redux определяет Redux как:Предсказуемый контейнер управления состоянием приложения JavaScript.

Это означает, что Redux не может работать в одиночку. Чтобы проявить свою мощь, его необходимо объединить с определенной внешней структурой уровня View. Слой View здесь включает, помимо прочего, React, Vue или Angular. Здесь мы будем использовать React в качестве уровня представления привязки, потому что Redux изначально родился в сообществе React как библиотека, спроектированная и разработанная для решения проблемы управления состоянием React. Это руководство даст вам интуитивное представление о «кризисе состояния» React и о том, как Redux разрешил его, чтобы вы могли лучше изучить Redux и понять, откуда он взялся и куда движется.

В последнее время React Hooks очень популярны, демонстрируя удивительный потенциал, и некоторые люди даже утверждают, что от Redux можно отказаться. На самом деле я считаю это утверждение не совсем правильным.Успех Redux обусловлен не только самим фреймворком, но и выстроенной вокруг него экосистемой, такой как Enhancers, Middlewares и redux-form, redux-immutable, и т. д., и даже существуют фреймворки верхнего уровня, основанные на Redux, такие как Dva и Rematch, которые закрепили Redux как короля сообщества React.

Интересно, что мы заметили, что библиотека связывания React для Redux, react-redux, теперь подвергается рефакторингу с помощью React Hooks, чтобы сделать код более совершенным и эффективным, поэтому я думаю, что React Hooks поначалу все еще находится в зачаточном состоянии, и небольшое количество ранние последователи Используйте его для создания лучших проектов или фреймворков React.React Hooks может улучшить эти предыдущие проекты и фреймворки, чтобы лучше способствовать дальнейшему процветанию экосистемы Redux, поэтому у нас есть основания полагать, что появление React Hooks, это сделает сообщество React более эффективным и профессиональным, а также поможет цепочке инструментов Redux стать легче, и, наконец, как отличная функция React, она отодвинет React и его экологию на большее расстояние.

Предварительные условия

Это руководство является кратким руководством по Redux и посвящено объяснению использования привязки с React, а понимание и освоение Redux — это относительно сложный контент для разработчика React, поэтому мы предполагаем, что вы читаете это руководство. необходимо иметь следующие резервы знаний:

  • Для функций ES6, классов,const, деструктуризация объекта, параметры функции по умолчанию и другие понятия хорошо понимают, конечно, если вы понимаете функциональное программирование, такое как чистые функции, неизменяемость и т. д.
  • Иметь хорошее представление о React, конечно, если у вас есть опыт самостоятельной разработки React-приложений не менее 5 страниц, будет лучше, вы можете обратиться к этой статьеРуководство по началу работыучиться
  • Понимать Node и npm и иметь соответствующий опыт установки зависимостей, вы можете обратиться кэтот учебникучиться

чему вы научитесь

В этом уроке мы сначала дадимАпплет To-Do с React(СравниватьПоследний урокЭто будет отправной точкой для изучения Redux. Когда вы ознакомитесь с этим исходным кодом и поймете его функции, вы можете закрыть его и начать наш учебник.

На основе этого шаблона, написанного на чистом React, мы проанализируем проблемы, которые React имеет при обработке состояния, и преимущества, которые дает рефакторинг с помощью Redux. Затем мы узнаем, как шаг за шагом преобразовать чистое приложение React в приложение Redux с помощью практических методов и, наконец, внедрить обновленную версию апплета списка дел.

код и конечный эффект

Исходный код, реализованный в этом руководстве, размещен на Github:

Вы можете просмотреть окончательный эффект кода через CodeSandbox:

Начните свое путешествие с Redux

Какой бы ни была шумиха вокруг Redux, на самом деле ее можно суммировать на картинке, которая также поможет вам задуматься о сути фронтенда:

Давайте сначала внимательно посмотрим на это изображение, и вы увидите это изображение в различных формах несколько раз позже в этом уроке. Мы надеемся, что после этого урока, когда вы думаете о Redux, картинка выше будет у вас в голове.

View

Сначала давайте посмотрим на View , во фронтенд-разработке мы называем этослой просмотра, который является эффектом, отображаемым для конечного пользователя.При изучении этого руководства наше представление — это React.

Store

По мере того, как работа, которую должно выполнять внешнее приложение, становится все более и более объемной, мы также выдвигаем требования к внешнему интерфейсу для поддержания «состояния». В React это «состояние» будет храниться вthis.state. В Redux это состояние будет храниться в Store.

Это хранилище можно рассматривать как интерфейсную «базу данных» в абстрактном смысле, которая сохраняет состояние внешнего интерфейса и распределяет эти состояния в представлении, так что представление отображает различный контент в соответствии с этими состояниями.

Обратите внимание, что Redux — это контейнер управления предсказуемым состоянием для приложений JavaScript.государственный контейнерЭто Магазин здесь.

Reducers

Веб-страницы, которые мы видим в нашей повседневной жизни, не статичны, а реагируют на «действия» пользователя, будь то переход на страницу или вход в систему и регистрация, эти действия изменят состояние текущего приложения.

В среде Redux роль редукторов заключается в том, чтобы реагировать на различные действия. Точнее, редукторыФункция JavaScript, отвечающая за обновление состояния в Магазине.

Когда у нас будет приблизительное понимание этих трех основных концепций, мы можем приступить к изучению Redux.

Подготовить исходный код

Клонируйте начальный шаблон кода React локально, войдите в репозиторий и переключитесь на ветку начального кода (исходный шаблон кода):

git clone https://github.com/pftom/redux-quickstart-tutorial.git
cd redux-quickstart-tutorial
git checkout initial-code

Установите зависимости проекта и откройте сервер разработки:

npm install
npm start

Затем сервер разработки React откроет браузер, и если вы увидите следующий эффект и сможете продолжить, код готов к работе:

намекать

Поскольку мы используемCreate React AppScaffolding, который использует сервер разработки Webpack (WDS) в качестве сервера разработки, поэтому просто сохраните файл при редактировании кода позже, и наше приложение React автоматически обновится, что очень удобно.

Исследуйте исходный код

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

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

Весь компонент кода React разработан следующим образом (сначала компонент, затем свойства, которыми обладает компонент):

  • TodoListИспользуется для отображения списка задач:
    • todos: Arrayпредставляет собой массив todo, где каждый элемент выглядит как{ id, text, completed }.
    • toggleTodo(id: number)это функция обратного вызова, которая будет вызываться при нажатии на задачу.
  • Todoявляется одним компонентом todo:
    • text: stringэто то, что будет отображаться в этой задаче.
    • completed: booleanОн используется для обозначения того, завершен ли элемент.Если он завершен, то стиль перечеркивает этот элемент.
    • onClick()это функция обратного вызова, которая будет вызываться при нажатии на эту задачу.
  • Linkэто кнопка, которая показывает фильтрацию:
    • active: booleanПредставитель выбран в это время, то эту кнопку нельзя нажать
    • onClick()Представляет функцию обратного вызова, которая будет вызываться при нажатии этой ссылки.
    • children: ReactComponentПоказать подкомпоненты
  • FooterИспользуется для отображения трех кнопок фильтра:
    • filter: stringПредставляет выбранную строку фильтра в это время, это[SHOW_ALL, SHOW_COMPLETED, SHOW_ACTIVE]один из них.
    • setVisibilityFilter()При нажатии репрезентативной ссылки будет установлен соответствующий щелкнутыйfilterфункция обратного вызова.
  • App— это корневой компонент React, который, наконец, объединяет другие компоненты и использует ReactDOM для их компиляции и рендеринга.stateВышеупомянутое определяет свойства, которые будут использовать вышеупомянутые компоненты, и определяет методы, которые будут использовать другие компоненты, а такжеnextTodoId,VisibilityFilters,getVisibleTodosДождитесь некоторых вспомогательных функций.

Подготовьте среду Redux

Мы знаем, что Redux можно использовать с различными средами разработки уровня представления, такими как React, Vue и Angular, а Redux — это просто контейнер управления состоянием, поэтому для использования Redux в React нам также необходимо установить соответствующие зависимости.

npm install redux
npm install react-redux

отличная работа! Теперь, когда все готово, я думаю, вам не терпится написать немного кода, связанного с Redux, не волнуйтесь, в следующем разделе мы представим подробную концепцию Redux Store и объясним через код, какая часть React он заменит.

Понимание магазина: единственный источник достоверных данных

Ранее мы упоминали, что роль Store в Redux заключается в сохранении состояния, что эквивалентно созданию простой «базы данных» во внешнем интерфейсе. Если в современных интерфейсных приложениях с богатыми состояниями каждое изменение состояния (например, нажатие кнопки) требует связи с серверной частью, среднее время отклика всего веб-сайта станет неприемлемым, а взаимодействие с пользователем будет ужасным.

По неполной статистике: "Веб-сайт может удерживать пользователя только 8S. Если вы не можете привлечь пользователей в течение 8S, или есть проблема с сайтом, то вы полностью потеряете пользователя!"

Поэтому, чтобы удовлетворить потребности пользователей в доступе, пионеры интеллектуального внешнего интерфейса начали внедрять внутреннюю концепцию «базы данных» во внешний интерфейс, чтобы большая часть состояния внешнего интерфейса могла обрабатываться непосредственно во внешнем интерфейсе. конец, без необходимости внутреннего вмешательства.

Реагировать на состояние "Кризис"

В React мы храним состояние в каждом компоненте.this.state, каждый компонентstateЭто личное для компонента.Если вы хотите управлять другим компонентом в одном компоненте, это довольно громоздко реализовать.

Мы будем использовать следующую диаграмму, чтобы продемонстрировать, почему это громоздко:

Компонент A является родителем компонентов B и C. Если компонент B хочет работать с компонентом C, то ему сначала нужно вызвать переданный ему родительский компонент A.handleClickметод, а затем измените родительский компонент Astate, а затем инициировать изменение компонента C с помощью механизма автоматического повторного рендеринга React.

Теперь, когда компонент B и компонент C находятся на одном уровне, вы можете не чувствовать никаких проблем с этим межкомпонентным изменением.Давайте посмотрим на другую картину:

Мы видим картинку выше, компонент B и компонент C отличаются на много уровней, а n на картинке может быть 10 и более. В настоящее время, если вы хотите изменить компонент C в компоненте B, вы должны поместить этоhandleClickМетод передается слой за слоем. Каждый раз, когда вы хотите изменить его, вы должны вызывать его, что довольно громоздко.

Если компонент C находится ниже по иерархии от компонента A, ситуация усложняется:

В это время не толькоhandleClickМетод передается вглубь компонента B, когда компонент B вызываетhandleClickметод, измените компонент Astate, когда он будет передан компоненту C по очереди, все компоненты между компонентом A и компонентом C вызовут повторный рендеринг, что приведет к огромным накладным расходам на рендеринг.Когда наше приложение становится все более и более сложным, эти накладные расходы становятся явно невыносимыми.

Спасатель: Магазин

React родился с первоначальным намерением писать пользовательские интерфейсы лучше и эффективнее, и он не должен и не должен нести ответственность за управление состоянием.

Так замученные пионеры фронтенда задумали большой запас. Нам вообще не нужно держать каждый компонент в отдельном состоянии, а напрямую извлекать состояние всех компонентов, аналогично дереву компонентов React, строитьЦентрализованное дерево состояний, это дереводерево состоянийс реакциейдерево компонентовСоответствие один к одному, что эквивалентно моделированию дерева компонентов React с сохранением состояния:

Как видите, мы удалили состояние компонента и заменили его деревом состояний, которое является обычным объектом JavaScript. Вложенная комбинация компонентов аналогична вложенности объектов.Это дерево состояний, смоделированное объектами JavaScript, является Store в Redux.

Когда мы извлекаем состояние компонента, становится довольно просто и эффективно использовать компонент B для работы с компонентом C.

Мы инициируем действие для обновления состояния C в компоненте B. Функция обновления, соответствующая этому действию, обновляет дерево состояний Store, а затем передает обновленное состояние C компоненту C, запуская повторную визуализацию компонента C.

Видно, что когда мы вводим этот механизм, взаимодействие между компонентом B и компонентом C может осуществляться независимо, не затрагивая другие компоненты в дереве компонентов React и не проходя глубокий уровень.handleClickфункция, не нужно ставить обновленнуюstateОн передается компоненту C слой за слоем, и производительность имеет качественный скачок.

В Redux Store все изменения состояния в приложениях React являются модификациями этого дерева объектов JavaScript, и все состояния получаются из этого дерева объектов JavaScript, а дерево состояний, представленное этим объектом JavaScript, становится всем приложением. Данные".

намочить руки

Теперь, когда мы понимаем, что Redux Store делает для React, давайте сразу применим Redux в React, чтобы увидеть, как волшебный Store может вмешаться и иметь такое большое значение.

Модифицируем исходный шаблон кода вsrc/index.js, измененный код выглядит следующим образом:

import React from "react";
import ReactDOM from "react-dom";
import App, { VisibilityFilters } from "./components/App";

import { createStore } from "redux";
import { Provider } from "react-redux";

const initialState = {
  todos: [
    {
      id: 1,
      text: "你好, 图雀",
      completed: false
    },
    {
      id: 2,
      text: "我是一只小小小小图雀",
      completed: false
    },
    {
      id: 3,
      text: "小若燕雀,亦可一展宏图!",
      completed: false
    }
  ],
  filter: VisibilityFilters.SHOW_ALL
};

const rootReducer = (state, action) => {
  return state;
};

const store = createStore(rootReducer, initialState);

ReactDOM.render(
  <Provider store={store}>
    <App />
  </Provider>,
  document.getElementById("root")
);

Как видите, приведенный выше код выполняет следующие действия:

  • Сначала мы выполнили операцию пакета направляющих, начиная сreduxЭкспортcreateStore,отreact-reduxэкспортируетсяProvider,отsrc/components/App.jsэкспортируется вVisibilityFilters.
  • Затем мы определяемinitialStateобъект, который будет использоваться в качестве данных начального состояния для хранилища, которое мы создадим позже, а также начальное значение дерева объектов JavaScript, о котором мы упоминали ранее.
  • Затем мы определяемrootReducerфункция, которая является стрелочной функцией, получаетstateа такжеactionзатем вернутьсяstate, эта функция еще не выполнила никакой работы, но это один из необходимых параметров для создания Store, мы подробно объясним это позже в редьюсерах.
  • Затем мы вызываем Redux API, который мы экспортировали ранее:createStoreфункция, переданная в определенномrootReducerа такжеinitialState, который порождает главный герой нашего раздела: store!
  • Наконец мыAppСамое внешнее использование компонентаProviderpackage и получите тот, который мы создали на предыдущем шагеstoreВ качестве параметра это гарантирует, что мы сможем получить доступ к состоянию в хранилище позже в дочернем компоненте.Providerдаreact-reduxAPI предоставляет библиотеку Redux в привязках React, используя ее для построения моста связи Redux и React.

Теперь, когда мы создали магазин и использует реагирование с помощью библиотеки привязки Reduxreact-reduxкоторый предоставилProviderКомпоненты объединяют Store с компонентами React. Давайте посмотрим на эффект после интеграции Store и React.

Открытьsrc/components/App.js, измените код следующим образом:

import React from "react";
import AddTodo from "./AddTodo";
import TodoList from "./TodoList";
import Footer from "./Footer";

import { connect } from "react-redux";

// 省略了 VisibilityFilters 和 getVisibleTodos 函数...

class App extends React.Component {
  constructor(props) {
    super(props);

    this.toggleTodo = this.toggleTodo.bind(this);
    this.onSubmit = this.onSubmit.bind(this);
    this.setVisibilityFilter = this.setVisibilityFilter.bind(this);
  }

  // 省略中间其他方法...

  render() {
    const { todos, filter } = this.props;

    return (
      <div>
        <AddTodo onSubmit={this.onSubmit} />
        <TodoList
          todos={getVisibleTodos(todos, filter)}
          toggleTodo={this.toggleTodo}
        />
        <Footer
          filter={filter}
          setVisibilityFilter={this.setVisibilityFilter}
        />
      </div>
    );
  }
}

const mapStateToProps = (state, props) => ({
  todos: state.todos,
  filter: state.filter
});

export default connect(mapStateToProps)(App);

Как видите, приведенный выше код выполняет следующие действия:

  • Сначала мы начинаем сreact-reduxБиблиотека привязки экспортируетсяconnectфункция.
  • Затем в нижней части файла мы определяемmapStateToPropsстрелочная функция, которая получаетstateа такжеprops,этоstateЭто дерево состояний объекта JavaScript, сохраненное в нашем хранилище, которое в настоящее время является тем, что мы определили в предыдущем файле.initialStateсодержание; этоpropsЭто оригинальный компонент React, с которым мы знакомы.props, это дляmapStateToPropsявляется необязательным параметром.mapStateToPropsФункции — это примитивы, которые могут одновременно манипулировать компонентами.propsи Store state, а затем объединить их с конечными реквизитами компонента (конечно, здесь мы не используем исходный контент реквизитов компонента) и передатьconnectфункция переданаAppкомпоненты.
  • connectфункция полученияmapStatePropsфункция, получитьmapStatePropsВозвращает конечное комбинированное состояние, которое затем вводится вAppкомпонент, вернуть новый компонент, а затем передать егоexport defaultэкспорт.
  • После вышеуказанной работы мыAppкомпоненты можно получить черезmapStateToPropsвернуть{ todos, filter }содержание, мы деконструируем объект изthis.propsполучатьtodosа такжеfilterАтрибуты.
  • Наконец, мы удаляем те, которые больше не нужныconstructorсерединаthis.stateсодержание.

Уведомление

connectНа самом деле это функция более высокого порядка.Функция высшего порядка относится к функции, которая может получать параметры, вызывать и возвращать другую функцию. здесьconnectполучивmapStateToPropsЗатем вызов возвращает новую функцию, которая затем получаетAppкомпонент в качестве параметра, черезmapStateToPropsинъекцияtodosа такжеfilterсвойство и, наконец, возвращает введенныйAppкомпоненты.

намекать

Вот почему мы можемAppкомпонент черезmapStateToPropsПолучите дерево состояний объекта JavaScript, сохраненное в Магазине, поскольку мы передалиProviderзавернутыйAppкомпоненты, и будетstoreпередается как атрибутProvider.

Воспроизведите пончик Redux

Теперь давайте взглянем на кольцевую диаграмму, которую мы упоминали в первом шаге. Сейчас мы находимся на первом этапе этого процесса, который заключается в передаче состояния в хранилище в представление. В частности, мы используем библиотеку привязки React Redux.react-reduxсерединаconnectосуществленный.

Сохраните изменения, если ваш сервер разработки React открыт, вы должны увидеть что-то вроде этого в своем браузере:

поздравляю! Вы успешно написали хранилище Redux, проделав треть пути к интеграции Redux в React. Подключив Store в React, вы успешно подключили данные между Redux и React и удалилиthis.state, вместо этого используйте состояние Storethis.state.

но! когда вы нажимаетеAdd Todoкнопку, ваш браузер должен показать красную ошибку, потому что мы удалилиthis.stateсодержание, поэтому вonSubmitметод чтенияthis.state.todosсообщит об ошибке. Не волнуйтесь, мы будем в следующем разделе:Actionкак устранить эти ошибки.

Понимание действия: единственный способ изменить состояние

Добро пожаловать в раздел Redux Action, давайте еще раз обратимся к диаграмме, упомянутой в предыдущем разделе:

В предыдущем разделе мы выполнили определенное действие в компоненте B для изменения содержимого в компоненте C, подробно проанализировали недостатки реализации полностью на основе React и представили концепцию Redux Store, чтобы объяснить, что нам нужно только построить глобальный Дерево состояний объекта JavaScript, а затем все изменения состояния выполняются путем изменения этого дерева состояний, а затем передачи измененного нового состояния соответствующему компоненту и запуска повторного рендеринга для достижения нашей цели. И мы объяснили, как передать состояние в Store компонентам React.

В этом разделе мы поговорим о том, как изменить состояние, сохраненное в Redux Store. Вернемся к знакомой кольцевой диаграмме состояний Redux:

Изменение состояния, сохраненного в Магазине, — это вторая часть приведенной выше картинки, то есть мы создали Магазин и сохранили в нем дерево состояний объектов JavaScript.Изменяем состояние, сохраненное в Магазине, с помощью условия «инициация действия обновления». .

Что такое действие?

В концептуальных терминах Redux существует один и только один способ обновить состояние Store: это вызватьdispatchфункция, передаваяactionк этой функции.

Действие — это простой объект JavaScript:

{ type: 'ADD_TODO', text: '我是一只小小小图雀' }

мы можем видетьactionСодержит тип действия и данные, необходимые для обновления состояния, гдеtypeтребуется, другой контент не является обязательным, здесь мы исключаемtype, плюс доп.text, инициированный от нашего имениtypeдляADD_TODOДействие заключается в том, что дополнительныйtextсодержание.

Поэтому, если нам нужно обновить состояние Store, нам нужен вызов функции, подобный следующему:

dispatch({ type: 'ADD_TODO', text: '我是一只小小小图雀' })

Использование создателей действий

Потому что, когда мы создаем действие, иногда некоторый контент фиксируется.Например, действие нашего учебника по добавлению списка дел имеет три поля, которыеtype,text,id, мы можем захотеть иметь возможностьdispatchЭто действие, то нам нужно каждый раз писать следующую длинную строку:

{ type: 'ADD_TODO', text: '我是一只小小小图雀' , id: 0}
{ type: 'ADD_TODO', text: '小若燕雀,亦可一展宏图' , id: 1}
...
{ type: 'ADD_TODO', text: '欢迎你加入图雀社区!' , id: 10}

Студенты, которые более знакомы с функциями JavaScript, могут знать, как решить эту проблему. Да, нам просто нужно определить функцию и пройти в параметрах, которые необходимо изменить.

let nextTodoId = 0;

const addTodo = text => ({
  type: "ADD_TODO",
  id: nextTodoId++,
  text
});

Эта функция, которая получает некоторые параметры, которые необходимо изменить, и возвращает действие, называется Action Creators в Redux.

Когда мы используем Action Creators для создания Actions, мы хотим изменить состояние Store следующим образом:

dispatch(addTodo('我是一只小小小图雀'))

Как видите, наша логика сильно упрощается, каждый раз новый"ADD_TODO"действие, вам нужно только передать соответствующий текст.

Интеграция с React

Поняв основную концепцию действия, давайте попробуем инициировать действие обновления в React.

Во-первых, мыsrcСоздано под папкойactionsпапку, затем вactionsсоздать папкуindex.jsфайл и добавьте внутрь следующих создателей действий:

let nextTodoId = 0;

export const addTodo = text => ({
  type: "ADD_TODO",
  id: nextTodoId++,
  text
});

Поскольку в приложении React, использующем Redux, нам потребуется создать большое количество действий или создателей действий, передовой опыт сообщества Redux рекомендует создавать отдельныйactionsПапка и напишите конкретную логику действий в этой папке.

Как видите, мы добавилиaddTodoСоздатель действий, который получаетtextпараметр и каждый раз увеличивать на единицуid, затем возвращается сidа такжеtext, а тип"ADD_TODO"Действие.

Затем мы модифицируемsrc/components/AddTodo.jsфайл, предыдущийonSubmitзаменено наdispatch(action)изменить состояние Магазина в виде:

import React from "react";
import { connect } from "react-redux";
import { addTodo } from "../actions";

const AddTodo = ({ dispatch }) => {
  let input;

  return (
    <div>
      <form
        onSubmit={e => {
          e.preventDefault();
          if (!input.value.trim()) {
            return;
          }
          dispatch(addTodo(input.value));
          input.value = "";
        }}
      >
        <input ref={node => (input = node)} />
        <button type="submit">Add Todo</button>
      </form>
    </div>
  );
};

export default connect()(AddTodo);

Как видите, приведенный выше код внес следующие изменения:

  • Сначала мы начинаем сreact-reduxэкспортируется вconnectФункция, отвечающая за состояние Store при инжекте сборки, в метод передается дополнительный компонент:dispatch, чтобы мы могли использовать его в компонентеpropsполучить этот метод. Обратите внимание, что мы используем деструктуризацию объекта в функциональном компоненте AddTodo, чтобы получитьdispatchметод.
  • Экспортировали то, что мы только что создалиaddTodoСоздатели действий.
  • После этого используемaddTodoперениматьinput.valueВведите значение, создайте тип"ADD_TODO"Действие и использованиеdispatchФункция отправляет это действие в Redux, запрашивая обновление содержимого Store.Обновление состояния Store требует работы Reducers, и мы подробно объясним это в Reducers.

Поскольку мы напрямую изменилиthis.stateизonSubmitзаменяетсяdispatchДействие, поэтому мы удаляемsrc/components/App.jsСоответствующий код, так как они нам сейчас не нужны:

import React from "react";
import AddTodo from "./AddTodo";
import TodoList from "./TodoList";
import Footer from "./Footer";

import { connect } from "react-redux";

// 省略 VisibilityFilters 和 getVisibleTodos ...

class App extends React.Component {
  constructor(props) {
    super(props);

    this.toggleTodo = this.toggleTodo.bind(this);
    this.setVisibilityFilter = this.setVisibilityFilter.bind(this);
  }

  toggleTodo(id) {
    const { todos } = this.state;

    this.setState({
      todos: todos.map(todo =>
        todo.id === id ? { ...todo, completed: !todo.completed } : todo
      )
    });
  }

  setVisibilityFilter(filter) {
    this.setState({
      filter: filter
    });
  }

  render() {
    const { todos, filter } = this.props;

    return (
      <div>
        <AddTodo />
        <TodoList
          todos={getVisibleTodos(todos, filter)}
          toggleTodo={this.toggleTodo}
        />
        <Footer
          filter={filter}
          setVisibilityFilter={this.setVisibilityFilter}
        />
      </div>
    );
  }
}

// 后面没有变化 ...

Вы можете видеть, что мы удалилиnextTodoId, потому что мы уже вsrc/actions/index.jsпереопределили его в , затем удалилиonSubmitметод; наконец, мы удаляем переданныйAddTodoкомпонентonSubmitметод.

Сохраните измененное содержимое, мы вводим содержимое в поле ввода апплета to-do, а затем нажимаемAdd Todoкнопку, мы обнаружили, что предыдущая ошибка больше не появлялась.

прискорбный вывод

В этом разделе мы завершили вторую часть кольцевой диаграммы состояний Redux, которая должна инициировать действие обновления. Сначала мы объясним, что такое действие и создатели действий, а затем передаемdispatch(action)способ инициировать действие, которое обновляет состояние в Store.

когда мы использовалиdispatch(action)之后,传递给子组件,用来修改父组件 State 的方法就不需要了,所以我们在代码中删除了它们。 в нашемAddTodoТаким образомonSubmit.

Но немного жаль, что хотя мы удалилиonSubmitметод, но то, о чем мы говорили и реализовывали в этом разделеdispatch(action)только до завершенияonSubmitПоловина функции метода состоит в том, чтобы инициировать действие модификации, но мы пока не можем изменить состояние в Store. Чтобы изменить состояние в магазине, нам нужно определить редукторы, которые реагируют на нашиdispatchДействие и измените соответствующие данные в Магазине в соответствии с требованиями Действия.

Понимание редюсеров: ответы на инструкции к действию

В этом разделе мы сразу же приходим к выводу о сожалении, оставленном в предыдущем разделе, что мы как будто выстрелили из пустой пушки,dispatchДействие было выполнено, но эффекта не было получено.

Во-первых, мы предлагаем нашу универсальную диаграмму состояния Redux:

Мы выполнили первые два шага, и остался только один последний шаг для интеграции Redux в React, который является ответом от компонентаdispatchВыходите Action, и обновляйте состояние в Store, которое в концепции Redux называется Reducers.

Очищенные редукторы

reducer— это обычная функция JavaScript, которая принимает два параметра:stateа такжеaction, первое — это дерево состояний объекта JavaScript, хранящееся в Store, а второе — наш компонент в компонентеdispatchэто Действие.

reducer(state, action) {
  // 对 state 进行操作
  return newState;
}

Редюсер выполняет соответствующие операции над состоянием в соответствии с инструкциями действия, а затем возвращает состояние после операции.Redux Store автоматически сохранит новое состояние.

Уведомление

Соглашение официального сообщества Redux о редюсере — это чистая функция, то есть мы не можем изменять его напрямую.state, вместо этого вы можете использовать{...}и другие методы деструктуризации объекта возвращают модифицированный новыйstate.

Например, мыstate = { a: 1, b: 2 }внести изменения вaВместо 3 мы должны сделать это:newState = { ...state, a: 3 }, вместоstate.a = 3. Это не модифицируется напрямую, а возвращает новый объект модификации, который мы называем модификацией «очищения».

Готов ответить на изменение действия

Разобравшись с концепцией Reducer, мы сразу отвечаем на наше предыдущее приложение в приложенииdispatchДействие, чтобы компенсировать сожаления, которые мы оставили в предыдущем разделе.

Открытьsrc/index.js,правильноrootReducerВнесите следующие изменения:

// ...

const rootReducer = (state, action) => {
  switch (action.type) {
    case "ADD_TODO": {
      const { todos } = state;

      return {
        ...state,
        todos: [
          ...todos,
          {
            id: action.id,
            text: action.text,
            completed: false
          }
        ]
      };
    }
    default:
      return state;
  }
};

// ...

Приведенный выше код делает несколько вещей:

  • Видно, что мы будемrootReducerвносить улучшения, от простого возврата к исходномуstate, становитсяswitchприговор, вswitchзаявление к действиюtypeВыносите суждения, а затем предпринимайте соответствующие действия.
  • когдаaction.typeимеет тип"ADD_TODO", мы изstateизъятыеtodos, затем используйте{...}грамматика даетtodosДобавьте новый объект элемента и установитеcompletedсобственностьfalseПредставляет, что эта задача не завершена и, наконец, проходит через другой уровень{...}синтаксис будет новыйtodosсливаться со старымstate, возвращает этот новыйstate.
  • когдаaction.typeне совпадаетswitchдля любого условия мы возвращаем значение по умолчаниюstate,ВыражатьstateОбновлений нет.

когда мыrootReducerПосле внесения вышеуказанных изменений в функцию Redux может отвечать подчиненному компоненту через функцию Reducer.dispatchотactionтеперь мы можем только ответитьaction.typeдля"ADD_TODO"действие, что означает добавление задачи.

Сохраните измененный код, откройте браузер, введите содержимое в поле ввода и нажмитеAdd Todoкнопку, веб-страница теперь должна правильно реагировать на ваши действия, и мы можем с радостью снова добавлять новые элементы списка дел.

резюме

В этом разделе мы реализовали наш первый адаптивный компонент.dispatchРедуктор действия, которое выходит, он судитaction.typeтипов, и на основе этих типовstateДелайте «очищенные» модификации, когдаaction.typeКогда нет соответствия ни для одного типа в Reducer, мы возвращаем оригиналstate.

Разобравшись с тремя концепциями Redux: Store, Action и Reducers, давайте посмотрим на другую картинку:

Мы уже видели подобную картинку раньше, но в этот раз мы добавили кое-что к этой картинке и выделили ее.dispatch,reducersа такжеconnectработа сделана.

  • dispatch(action)Используется в компонентах React для выдачи директив, которые изменяют состояние, хранящееся в Store. Когда нам нужно добавить новую задачу, она заменяет ранее определенную в компонентеonSubmitметод.
  • reducer(state, action)Используется для изменения соответствующей части сохраненного состояния в Store в соответствии с этой инструкцией. Когда нам нужно добавить новую задачу, она заменяет ранее определенную в компонентеthis.setStateработать.
  • connect(mapStateToProps)Используется для передачи обновленных данных в компонент, а затем запускает React для повторного рендеринга, показывая последнее состояние. Он создает мост для передачи данных между Redux и React.

Теперь вы изучили все основные концепции Redux, и наше приложение полностью интегрировало Redux. Однако нам еще предстоит проделать небольшую работу, а именно полностью реорганизовать все приложение для использования Redux. существуетСледующий урокВ , мы будем использовать то, что мы узнали в трех разделах выше, для пошагового рефакторинга остальной части нашего приложения todo в Redux, так что продолжайте читать.

Хотите узнать больше интересных практических технических руководств? ПриходитьСообщество ТукеМагазин вокруг.