Управление состоянием интерфейсных приложений становится все более сложным. С наступлением эпохи большого фронтенда фронтенд все больше внимания уделяет логике обработки, а не просто фокусируется на улучшении уровня пользовательского интерфейса.Появление фронтенд-фреймворков в лице React значительно упростило сложность написания UI интерфейсов. Хотя React предоставляет механизм состояния для управления состоянием, а также соглашения о разработке, такие как «продвижение состояния», эти решения подходят только для небольших приложений.Когда ваше внешнее приложение имеет более 10 страниц, как сделать состояние приложения управляемым , Сделать совместную разработку эффективной стало насущной проблемой, и Redux был создан для решения этих проблем! «Единый источник достоверных данных», односторонний поток данных и «чистые редукторы функций», предложенные Redux, значительно упрощают интерфейсную логику, позволяя нам писать произвольно сложные интерфейсные приложения эффективным и совместным образом. Это руководство посвящено объяснению Redux в коротких текстах и пониманию концепций и сути Redux на практике.
Добро пожаловать в серию обучающих пакетов Redux:
- Встреча с обучающей сумкой Redux (1): спасите кризис состояния React (то есть этот)
- Встреча с обучающими пакетами Redux (2): Куй железо, пока горячо, полный рефакторинг
- Образовательный пакет Redux (3): выполнение своих обязанностей и восстановление своих первоначальных устремлений.
Этот учебник принадлежитМаршрут обучения фронтенд-инженера 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:
- Чистый исходный код React:Адрес источника.
- Рефакторинг исходного кода с использованием Redux:Адрес источника.
Вы можете просмотреть окончательный эффект кода через CodeSandbox:
- Чистый эффект реакции:окончательный адрес действия.
- Эффект после рефакторинга с Redux:окончательный адрес действия.
Начните свое путешествие с 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
Самое внешнее использование компонентаProvider
package и получите тот, который мы создали на предыдущем шагеstore
В качестве параметра это гарантирует, что мы сможем получить доступ к состоянию в хранилище позже в дочернем компоненте.Provider
даreact-redux
API предоставляет библиотеку 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, так что продолжайте читать.
Хотите узнать больше интересных практических технических руководств? ПриходитьСообщество ТукеМагазин вокруг.