create by jsliang on 2019-3-26 09:26:53
Recently revised in 2019-4-7 03:04:01
Привет друзья, если вы считаете, что эта статья неплохая, не забудьте датьstar, друзья моиstarЭто моя мотивация продолжать обновлять!Адрес GitHub
【2019-08-16】Привет друзья, потому чтоjsliangБиблиотека документации подверглась рефакторингу, некоторые ссылки в этой статье могут быть неработоспособны, иjsliangИзвините за отсутствие сил поддерживать старые статьи на стороне Наггетс. Для тех, кому нужно получать последние статьи, щелкните адрес GitHub выше и перейдите в библиотеку документов, чтобы просмотреть скорректированные статьи.
каталог
Чем отличается передок без закидывания от соленой рыбы?
2 Предисловие
Отказ от ответственности: эта серия статей в основном относится к реальному видео MOOC React и написана в сочетании с личным пониманием:
Эта демонстрация обновляет Redux на основе ReactDemoOne, объясняет промежуточное ПО Redux-Thunk и Redux-Saga и, наконец, использует React-Redux для рефакторинга проекта.
Итак, друзья, которые не читали первую статью, могут ознакомиться с ней:
Если вы хотите прочитать статью об этом исходном коде, вы можете перейти по следующему адресу для загрузки:
Обратите внимание, что код в этой статье находится в каталоге TodoListUpgrade и имеет четыре папки, соответствующие:
- Redux-Thunk — на основе Redux-Base
redux-thunk
конфигурация промежуточного программного обеспечения - Redux-Saga — на основе Redux-Base
redux-saga
конфигурация промежуточного программного обеспечения - React-Redux — быть TodoList
react-redux
переделывать
Конечный каталог проекта Redux-Base выглядит следующим образом, вы можете создать пустой файл и сохранить его, и вы будете использовать его позже:
Три элемента инициализации
ПолучатьРеагировать серииВ коде каталога Simpify скопируйте его в Redux-Base, и приложение, измененное на TodoList, будет небольшим преобразованием TodoList.
Здесь мы начинаем модифицировать:
- src/index.js
Сведения о коде
import React from 'react';
import ReactDOM from 'react-dom';
import TodoList from './TodoList';
ReactDOM.render(<TodoList />, document.getElementById('root'));
- src/
App.jsTodoList.js
Сведения о коде
import React, { Component } from 'react';
import './index.css';
class TodoList extends Component {
render() {
return (
<div className="App">
Hello TodoList!
</div>
);
}
}
export default TodoList;
- src/index.css
Сведения о коде
/* 尚未进行编写 */
В этот момент мы запускаем в терминалеnpm run start
, отображаемый результат:
Четыре с помощью Ant Design
- Официальный сайт Ant Design:ant.design/index-cn
Давайте начнем использовать Ant Design в проекте TodoList:
- Установить:
npm i antd -S
- использовать:
- src/TodoList.js
Сведения о коде
import React, { Component } from 'react'; // 引入 React 及其 Component
import './index.css'; // 引入 index.css
import { Input, Button, List } from 'antd'; // 1. 引入 antd 的列表
import 'antd/dist/antd.css'; // 2. 引入 antd 的样式
// 3. 定义数据
const data = [
'这是非常非常非常长的让人觉得不可思议的但是它语句通顺的第一条 TodoList',
'这是非常非常非常长的让人觉得不可思议的但是它语句通顺的第二条 TodoList',
'这是非常非常非常长的让人觉得不可思议的但是它语句通顺的第三条 TodoList',
'这是非常非常非常长的让人觉得不可思议的但是它语句通顺的第四条 TodoList',
];
class TodoList extends Component {
render() {
return (
<div className="todo">
<div className="todo-title">
<h1>TodoList</h1>
</div>
{/* 4. 使用 Input、Button 组件 */}
<div className="todo-action">
<Input placeholder='todo' className="todo-input" />
<Button type="primary" className="todo-submit">提交</Button>
</div>
{/* 5. 使用 List 组件 */}
<div className="todo-list">
<List
size="large"
bordered
dataSource={data}
renderItem={(item, index) => (<List.Item>{index + 1} - {item}</List.Item>)}
/>
</div>
</div>
);
}
}
export default TodoList;
- src/index.css
Сведения о коде
.todo {
width: 1000px;
margin: 20px auto 0;
padding: 30px;
border: 1px solid #ccc;
border-radius: 10px;
}
.todo-title {
text-align: center;
}
.todo-action .todo-input {
width: 200px;
}
.todo-action .todo-submit {
margin-left: 10px;
}
.todo-list {
margin-top: 30px;
}
Здесь шаги, которые мы предпринимаем, чтобы обратиться к Ant Design, примерно таковы:
- И введение компонентов ввода, кнопок, списка
- Ввел ангдный стиль
- определить данные
- Используйте компоненты Input, Button
- Использование компонента списка
Теперь страница выглядит так:
5. Использование Редукса
Я думаю, что необходимо использовать Redux, чтобы испытать его, прежде чем объяснять Redux:
- Установите Редукс:
npm i redux -S
- Давайте сначала попробуем использовать Redux:
Создайте каталог store в каталоге src для хранения данных Redux.В этом каталоге есть два файла, reducer.js и index.js.
первый, пишем файл reducer.js, который определяет и обрабатывает данные:
- src/store/reducer.js
Сведения о коде
// 1. 我们定义一个数据 defaultState
const defaultState = {
inputValue: '',
todoList: [
'这是非常非常非常长的让人觉得不可思议的但是它语句通顺的第一条 TodoList',
'这是非常非常非常长的让人觉得不可思议的但是它语句通顺的第二条 TodoList',
'这是非常非常非常长的让人觉得不可思议的但是它语句通顺的第三条 TodoList',
'这是非常非常非常长的让人觉得不可思议的但是它语句通顺的第四条 TodoList',
]
}
// 2. 我们将数据 defaultState 最终以 state 形式导出去
export default (state = defaultState, action) => {
return state;
}
потом, мы пишем файл index.js, который используется для создания хранилища данных через метод createStore и экспортируем его в TodoList.js для использования.
- src/store/index.js
Сведения о коде
import { createStore } from 'redux'; // 3. 我们引用 redux 这个库中的 createStore
import reducer from './reducer'; // 4. 我们引用 reducer.js 中导出的数据
// 5. 我们通过 redux 提供的方法 reducer 来构建一个数据存储仓库
const store = createStore(reducer);
// 6. 我们将 store 导出去
export default store;
наконец, мы ссылаемся на store/index.js в TodoList.js и используем его в списке, а также распечатываем данные, переданные нам магазином:
- src/TodoList.js
Сведения о коде
import React, { Component } from 'react'; // 引入 React 及其 Component
import './index.css'; // 引入 index.css
import { Input, Button, List } from 'antd'; // 引入 antd 的组件
import 'antd/dist/antd.css'; // 引入 antd 的样式
import store from './store'; // 7. 引入 store,你可以理解为 store 提供数据。./store 是 ./store/index.js 的缩写
class TodoList extends Component {
// 8. 在 constructor 中通过 store.getState() 方法来获取数据,并赋值为 state
constructor(props) {
super(props);
// 9. 我们尝试在 Console 中打印 store.getState()
console.log(store.getState());
this.state = store.getState();
}
render() {
return (
<div className="todo">
<div className="todo-title">
<h1>TodoList</h1>
</div>
{/* 使用 Input、Button 组件 */}
<div className="todo-action">
<Input placeholder='todo' className="todo-input" />
<Button type="primary" className="todo-submit">提交</Button>
</div>
{/* 使用 List 组件 */}
{/* 10. 将原先的 data 换成 state 中的 todoList */}
<div className="todo-list">
<List
size="large"
bordered
dataSource={this.state.todoList}
renderItem={(item, index) => (<List.Item>{index + 1} - {item}</List.Item>)}
/>
</div>
</div>
);
}
}
export default TodoList;
На данный момент мы смотрим на консоль и страницу Chrome и видим, что она работает:
Таким образом, мы завершили [Query] данных в redux, то как мы [модифицируем] данные в redux, а что redux? Давай пойдем.
Шесть исследований Redux
Если вы думаете, что вы можете прочитать буклет или официальный сайт и более четко понять, пожалуйста, проверьте его сами. Следующие моменты предназначены только для справки.
6.1 Redux-плагины
- Установка: найдите соответствующий подключаемый модуль Chrome в Интернете или загрузите его с Baidu или через
npm install --save-dev redux-devtools
Установите его инструменты разработчика. - использовать:
- Закройте браузер и снова откройте, снова откройте консоль (F12), введите строку Redux, указывающую, что вы еще не установили код.
- Перейдите на index.js, чтобы установить код.
- Проверьте состояние и обнаружите, что данные есть, а плагин Redux установлен.
src/store/index.js
Сведения о коде
import { createStore } from 'redux';
import reducer from './reducer';
// 如果安装了 Redux 工具,则在这里可以直接使用该工具
const store = createStore(
reducer,
window.__REDUX_DEVTOOLS_EXTENSION__ && window.__REDUX_DEVTOOLS_EXTENSION__()
);
export default store;
6.2 Объяснение очков знаний Redux
Из-за определения React самого себя: «библиотека JavaScript для создания пользовательских интерфейсов».
Итак, когда мы находимся в реакции, если нуждаются в компонентах братьев коммуникаций, такие как темные круги слева от изображения выше, чтобы отправить данные в верхнюю (первую строку) круга, нам нужно много карманного изгиба, что привело к Связь данных очень неприятно.
Появление Redux должно компенсировать этот неприятный метод связи: установить центральный механизм для облегчения связи между компонентами. Таким образом, в правой части рисунка выше показан метод планирования.
Итак, каков механизм запуска/работы Redux? Анализируем по следующим картинкам:
На приведенной выше диаграмме мы предполагаем:
- Синий (компонент React): заемщик
- Желтый (создатели действий): действие по заимствованию книг
- Апельсин (Магазин): Библиотекарь
- Фиолетовый (редуктор): система
Его процесс можно понять так: сначала заемщик идет на стойку регистрации (действие заимствования), чтобы подать заявку на получение заимствования у библиотекаря, библиотекарь помогает ему найти информацию о книге в системе, затем заставляет компьютер вернуть информацию и, наконец, сообщает ему идти Где взять/как использовать.
В обмен на обычный случай, то есть: когда компонент (компоненты реагирования) должны вызывать данные, он инициирует запрос на создателя (Action Creators), менеджер уведомлений Создателя (Store), менеджер пошел находить соответствующую информацию (редукторы ) Получите информацию обратно, а затем сказали сборку.
В процессе мы будем использовать некоторые общие/основные API Redux:
-
createStore
: создать магазин -
store.dispatch
: действие отправки -
store.getState
: Получить все содержимое данных магазина -
store.subscribe
: отслеживать изменения в магазине, метод будет выполняться при изменении магазина.
Далее мы подробнее объясним вышеупомянутые точки знаний через ввод входных данных, отправку данных кнопкой и удаление элементов списка TodoItem.
Модификация данных Seven Redux
Теперь давайте начнем объяснять изменение данных Redux через ввод входных данных, отправку данных кнопкой и удаление элементов списка TodoItem.
7.1 Ввод исходных данных
- src/TodoList.js
Сведения о коде
import React, { Component } from 'react'; // 引入 React 及其 Component
import './index.css'; // 引入 index.css
import { Input, Button, List } from 'antd'; // 引入 antd 的组件
import 'antd/dist/antd.css'; // 引入 antd 的样式
import store from './store'; // 引入 store,你可以理解为 store 提供数据。./store 是 ./store/index.js 的缩写
class TodoList extends Component {
// 在 constructor 中通过 store.getState() 方法来获取数据,并赋值为 state
constructor(props) {
super(props);
// 我们尝试在 Console 中打印 store.getState()
// console.log(store.getState());
this.state = store.getState();
// 2. 定义 handleInputChange
this.handleInputChange = this.handleInputChange.bind(this);
// 7. 绑定方法 handleStoreChange 来处理 Redux 返回回来的数据
this.handleStoreChange = this.handleStoreChange.bind(this);
store.subscribe(this.handleStoreChange);
}
render() {
return (
<div className="todo">
<div className="todo-title">
<h1>TodoList</h1>
</div>
{/* 使用 Input、Button 组件 */}
<div className="todo-action">
{/* 1. Input 绑定 handleInputChange 事件 */}
<Input
placeholder='todo'
className="todo-input"
value={this.state.inputValue}
onChange={this.handleInputChange}
/>
<Button
type="primary"
className="todo-submit"
>
提交
</Button>
</div>
{/* 使用 List 组件 */}
{/* 将原先的 data 换成 state 中的 todoList */}
<div className="todo-list">
<List
size="large"
bordered
dataSource={this.state.todoList}
renderItem={(item, index) => (<List.Item>{index + 1} - {item}</List.Item>)}
/>
</div>
</div>
);
}
// 3. 编写 handleInputChange
handleInputChange(e) {
// 4. 通过 action,将数据传递给 store
const action = {
type: 'change_input_value',
value: e.target.value
}
store.dispatch(action);
}
// 8. 在 handleStoreChange 中处理数据
handleStoreChange() {
this.setState(store.getState());
}
}
export default TodoList;
- src/store/reducer.js
Сведения о коде
// 定义一个数据 defaultState
const defaultState = {
inputValue: '',
todoList: [
// '这是非常非常非常长的让人觉得不可思议的但是它语句通顺的第一条 TodoList',
// '这是非常非常非常长的让人觉得不可思议的但是它语句通顺的第二条 TodoList',
// '这是非常非常非常长的让人觉得不可思议的但是它语句通顺的第三条 TodoList',
// '这是非常非常非常长的让人觉得不可思议的但是它语句通顺的第四条 TodoList',
]
}
// 将数据 defaultState 最终以 state 形式导出去
export default (state = defaultState, action) => {
// 5. 打印 state 和 action
console.log(state);
console.log(action);
// 6. 在 reducer.js 中获取数据,并 return 回去处理结果
if(action.type === 'change_input_value') {
const newState = JSON.parse(JSON.stringify(state));
newState.inputValue = action.value;
return newState
}
return state;
}
Теперь давайте проанализируем (или прочитаем примечания к коду, чтобы понять), что мы сделали, когда модифицировали код:
- В компоненте Input мы даем ему
onChange
ограниченный по времениhandleInputChange
мероприятие. - определение
handleInputChange
метод. - записывать
handleInputChange
метод. - мы в
handleInputChange
написано наaction
,пройти черезdispatch
Будуaction
ToList.js redux передается из редуктора .js. - печать в редукторе.js
state
а такжеaction
. - Redux получен в reducer.js
state
а такжеaction
, то ставим новыйnewState
Вернуться к спине (чтобы вернуться в SRC / Store / index.js, обратно в SRC / ToList.js), вы можете получить желаемый ToList.js обратной связи. - в TodoList
constructor
прошедшийstore.subscribe
Привяжите метод обработки для обработки данных, возвращаемых Redux.handleStoreChange
. - существует
handleStoreChange
мы напрямуюsetState
Состояние, возвращаемое Redux, т.е.store.getState()
.
В настоящее время, если мы посмотрим на точки знаний Redux в главе 6.2, мы обнаружим, что точки знаний гладкие.
Ссылка: Счетчик
Сведения о коде
import { createStore } from 'redux';
/**
* 这是一个 reducer,形式为 (state, action) => state 的纯函数。
* 描述了 action 如何把 state 转变成下一个 state。
*
* state 的形式取决于你,可以是基本类型、数组、对象、
* 甚至是 Immutable.js 生成的数据结构。惟一的要点是
* 当 state 变化时需要返回全新的对象,而不是修改传入的参数。
*
* 下面例子使用 `switch` 语句和字符串来做判断,但你可以写帮助类(helper)
* 根据不同的约定(如方法映射)来判断,只要适用你的项目即可。
*/
function counter(state = 0, action) {
switch (action.type) {
case 'INCREMENT':
return state + 1;
case 'DECREMENT':
return state - 1;
default:
return state;
}
}
// 创建 Redux store 来存放应用的状态。
// API 是 { subscribe, dispatch, getState }。
let store = createStore(counter);
// 可以手动订阅更新,也可以事件绑定到视图层。
store.subscribe(() =>
console.log(store.getState())
);
// 改变内部 state 惟一方法是 dispatch 一个 action。
// action 可以被序列化,用日记记录和储存下来,后期还可以以回放的方式执行
store.dispatch({ type: 'INCREMENT' });
// 1
store.dispatch({ type: 'INCREMENT' });
// 2
store.dispatch({ type: 'DECREMENT' });
// 1
7.2 Кнопка отправки данных
Ниже мы приводим событие Enter для ввода и событие отправки с помощью кнопки.Друзья могут обратиться к событию ввода ввода, написать его самостоятельно, а затем просмотреть эту главу после написания, и вы получите больше.
src/TodoList.js
Сведения о коде
import React, { Component } from 'react'; // 引入 React 及其 Component
import './index.css'; // 引入 index.css
import { Input, Button, List } from 'antd'; // 引入 antd 的组件
import 'antd/dist/antd.css'; // 引入 antd 的样式
import store from './store'; // 引入 store,你可以理解为 store 提供数据。./store 是 ./store/index.js 的缩写
class TodoList extends Component {
// 在 constructor 中通过 store.getState() 方法来获取数据,并赋值为 state
constructor(props) {
super(props);
// 我们尝试在 Console 中打印 store.getState()
// console.log(store.getState());
this.state = store.getState();
// 处理 handleInputChange 方法
this.handleInputChange = this.handleInputChange.bind(this);
// 绑定方法 handleStoreChange 来处理 Redux 返回回来的数据
this.handleStoreChange = this.handleStoreChange.bind(this);
store.subscribe(this.handleStoreChange);
// 2. 处理 handleAddItem 方法
this.handleAddItem = this.handleAddItem.bind(this);
// 7. 处理 handleInputKeyUp 方法
this.handleInputKeyUp = this.handleInputKeyUp.bind(this);
}
render() {
return (
<div className="todo">
<div className="todo-title">
<h1>TodoList</h1>
</div>
{/* 使用 Input、Button 组件 */}
<div className="todo-action">
{/* Input 绑定 handleInputChange 事件 */}
{/* 6. Input 绑定回车事件:handleInputKeyUp */}
<Input
placeholder='todo'
className="todo-input"
value={this.state.inputValue}
onChange={this.handleInputChange}
onKeyUp={this.handleInputKeyUp}
/>
{/* 1. 为 Button 定义点击执行 handleAddItem 方法 */}
<Button
type="primary"
className="todo-submit"
onClick={this.handleAddItem}
>
提交
</Button>
</div>
{/* 使用 List 组件 */}
{/* 将原先的 data 换成 state 中的 todoList */}
<div className="todo-list">
<List
size="large"
bordered
dataSource={this.state.todoList}
renderItem={(item, index) => (<List.Item>{index + 1} - {item}</List.Item>)}
/>
</div>
</div>
);
}
// 编写 handleInputChange 方法
handleInputChange(e) {
// 通过 dispatch(action),将数据传递给 store
const action = {
type: 'change_input_value',
value: e.target.value
}
store.dispatch(action);
}
// 在 handleStoreChange 中处理数据
handleStoreChange() {
this.setState(store.getState());
}
// 3. 编写 handleAddItem 方法
handleAddItem() {
// 4. 通过 dispatch(action),将数据传递给 store
const action = {
type: 'add_todo_item'
}
store.dispatch(action);
}
// 8. 为 Input 的 keyUp 方法 handleInputKeyUp 绑定 handleAddItem
handleInputKeyUp(e) {
if(e.keyCode === 13) {
this.handleAddItem();
}
}
}
export default TodoList;
src/store/reducer.js
Сведения о коде
// 定义一个数据 defaultState
const defaultState = {
inputValue: '',
todoList: [
// '这是非常非常非常长的让人觉得不可思议的但是它语句通顺的第一条 TodoList',
// '这是非常非常非常长的让人觉得不可思议的但是它语句通顺的第二条 TodoList',
// '这是非常非常非常长的让人觉得不可思议的但是它语句通顺的第三条 TodoList',
// '这是非常非常非常长的让人觉得不可思议的但是它语句通顺的第四条 TodoList',
]
}
// 将数据 defaultState 最终以 state 形式导出去
export default (state = defaultState, action) => {
// 打印 state 和 action
// console.log(state);
// console.log(action);
// 在 reducer.js 中获取数据,并 return 回去处理结果
if(action.type === 'change_input_value') {
const newState = JSON.parse(JSON.stringify(state));
newState.inputValue = action.value;
return newState;
}
// 5. 在 reducer.js 中获取数据,并 return 回去处理结果
if(action.type === 'add_todo_item') {
const newState = JSON.parse(JSON.stringify(state));
newState.todoList.push(newState.inputValue);
newState.inputValue = '';
return newState;
}
return state;
}
В это время все наши события отправки кнопок обрабатываются, и в это время реализуется функция страницы:
Хорошо, давайте снова разберем процесс:
- Определить выполнение щелчка для кнопки
handleAddItem
метод - иметь дело с
handleAddItem
метод - записывать
handleAddItem
метод - пройти через
dispatch(action)
, передавая данные вstore
- Получите данные в reducer.js и верните их для обработки результата
- Ввод связывает событие возврата каретки:
handleInputKeyUp
- иметь дело с
handleInputKeyUp
метод - для метода ввода keyUp
handleInputKeyUp
связыватьhandleAddItem
Стоит отметить, что когда мы находимся в Input, мы сделалиhandleStoreChange
обработка, поэтому не пишемstore.subscribe()
Для мониторинга изменений данных, поэтому друзья должны обратить внимание на общий процесс.
7.3 Удаление элемента списка TodoItem
Затем мы добавим событие удаления к щелчку элемента списка.
src/TodoList.js
Сведения о коде
import React, { Component } from 'react'; // 引入 React 及其 Component
import './index.css'; // 引入 index.css
import { Input, Button, List } from 'antd'; // 引入 antd 的组件
import 'antd/dist/antd.css'; // 引入 antd 的样式
import store from './store'; // 引入 store,你可以理解为 store 提供数据。./store 是 ./store/index.js 的缩写
class TodoList extends Component {
// 在 constructor 中通过 store.getState() 方法来获取数据,并赋值为 state
constructor(props) {
super(props);
// 我们尝试在 Console 中打印 store.getState()
// console.log(store.getState());
this.state = store.getState();
// 处理 handleInputChange 方法
this.handleInputChange = this.handleInputChange.bind(this);
// 绑定方法 handleStoreChange 来处理 Redux 返回回来的数据
this.handleStoreChange = this.handleStoreChange.bind(this);
store.subscribe(this.handleStoreChange);
// 处理 handleAddItem 方法
this.handleAddItem = this.handleAddItem.bind(this);
// 处理 handleInputKeyUp 方法
this.handleInputKeyUp = this.handleInputKeyUp.bind(this);
}
render() {
return (
<div className="todo">
<div className="todo-title">
<h1>TodoList</h1>
</div>
{/* 使用 Input、Button 组件 */}
<div className="todo-action">
{/* Input 绑定 handleInputChange 事件 */}
{/* Input 绑定回车事件:handleInputKeyUp */}
<Input
placeholder='todo'
className="todo-input"
value={this.state.inputValue}
onChange={this.handleInputChange}
onKeyUp={this.handleInputKeyUp}
/>
{/* 为 Button 定义点击执行 handleAddItem 方法 */}
<Button
type="primary"
className="todo-submit"
onClick={this.handleAddItem}
>
提交
</Button>
</div>
{/* 使用 List 组件 */}
{/* 将原先的 data 换成 state 中的 todoList */}
{/* 1. 列表点击事件绑定 handleDeleteItem 方法 */}
<div className="todo-list">
<List
size="large"
bordered
dataSource={this.state.todoList}
renderItem={(item, index) => (
<List.Item onClick={this.handleDeleteItem.bind(this, index)}>{index + 1} - {item}</List.Item>
)}
/>
</div>
</div>
);
}
// 编写 handleInputChange 方法
handleInputChange(e) {
// 通过 dispatch(action),将数据传递给 store
const action = {
type: 'change_input_value',
value: e.target.value
}
store.dispatch(action);
}
// 在 handleStoreChange 中处理数据
handleStoreChange() {
this.setState(store.getState());
}
// 编写 handleAddItem 方法
handleAddItem() {
// 通过 dispatch(action),将数据传递给 store
const action = {
type: 'add_todo_item'
}
store.dispatch(action);
}
// 为 Input 的 keyUp 方法 handleInputKeyUp 绑定 handleAddItem
handleInputKeyUp(e) {
if(e.keyCode === 13) {
this.handleAddItem();
}
}
// 2. 编写 handleDeleteItem 方法
handleDeleteItem(index) {
console.log(index);
// 3. 通过 dispatch(action),将数据传递给 store
const action = {
type: 'delete_todo_item',
index
}
store.dispatch(action);
}
}
export default TodoList;
src/store/reducer.js
Сведения о коде
// 定义一个数据 defaultState
const defaultState = {
inputValue: '',
todoList: [
// '这是非常非常非常长的让人觉得不可思议的但是它语句通顺的第一条 TodoList',
// '这是非常非常非常长的让人觉得不可思议的但是它语句通顺的第二条 TodoList',
// '这是非常非常非常长的让人觉得不可思议的但是它语句通顺的第三条 TodoList',
// '这是非常非常非常长的让人觉得不可思议的但是它语句通顺的第四条 TodoList',
]
}
// 将数据 defaultState 最终以 state 形式导出去
export default (state = defaultState, action) => {
// 打印 state 和 action
// console.log(state);
// console.log(action);
// 在 reducer.js 中获取数据,并 return 回去处理结果
if(action.type === 'change_input_value') {
const newState = JSON.parse(JSON.stringify(state));
newState.inputValue = action.value;
return newState;
}
// 在 reducer.js 中获取数据,并 return 回去处理结果
if(action.type === 'add_todo_item') {
const newState = JSON.parse(JSON.stringify(state));
newState.todoList.push(newState.inputValue);
newState.inputValue = '';
return newState;
}
// 4. 在 reducer.js 中获取数据,并 return 回去处理结果
if(action.type === 'delete_todo_item') {
const newState = JSON.parse(JSON.stringify(state));
newState.todoList.splice(action.index, 1);
return newState;
}
return state;
}
Теперь давайте сделаем функциональную демонстрацию:
Давайте посмотрим на наши идеи программирования:
- Событие щелчка по списку привязано к методу handleDeleteItem. На данный момент, в связи с необходимостью привязки
this
и передать значениеindex
, т.е. два значения, поэтому мы прямо в коде:this.handleDeleteItem.bind(this, index)
- Напишите метод handleDeleteItem
- Передать данные в магазин через диспетчеризацию (действие)
- Получите данные в reducer.js и верните их для обработки результата
Таким образом, мы завершили удаление элемента списка.
На данный момент мы знакомы с методами сбора и модификации данных Reudx.
Восьмая оптимизация: извлечь тип в действии
В приведенной выше главе мы завершили построение TodoList, можно сказать, что сделали это.
Но, знаете, эта статья называется: [React Demo Two — TodoList Upgrade]
То есть мы не только обновляемся до Redux, но и продолжаем обновление, чтобы подготовить почву для разработки масштабных проектов.
Поэтому этот раздел начинаем оптимизировать.
В приведенном выше коде мы не нашли насaction
изtype
Написано ли оно в TodoList.js, и с ним сложно разобраться, если их слишком много?
change_input_value
add_todo_item
delete_todo_item
Итак, нам нужно обработать следующий тип, мы добавляем новый actionTypes.js в директорию хранилища:
src/store/actionTypes.js
Сведения о коде
// 1. 定义 actionTypes
export const CHANGE_INPUT_VALUE = 'change_input_value';
export const ADD_TODO_ITEM = 'add_todo_item';
export const DELETE_TODO_ITEM = 'delete_todo_item';
Затем в TodoList.js и reducer.js используйте:
src/TodoList.js
Сведения о коде
import React, { Component } from 'react'; // 引入 React 及其 Component
import './index.css'; // 引入 index.css
import { Input, Button, List } from 'antd'; // 引入 antd 的组件
import 'antd/dist/antd.css'; // 引入 antd 的样式
import store from './store'; // 引入 store,你可以理解为 store 提供数据。./store 是 ./store/index.js 的缩写
import { CHANGE_INPUT_VALUE, ADD_TODO_ITEM, DELETE_TODO_ITEM } from './actionTypes'; // 2. 引用 actionTypes
class TodoList extends Component {
// 在 constructor 中通过 store.getState() 方法来获取数据,并赋值为 state
constructor(props) {
super(props);
// 我们尝试在 Console 中打印 store.getState()
// console.log(store.getState());
this.state = store.getState();
// 处理 handleInputChange 方法
this.handleInputChange = this.handleInputChange.bind(this);
// 绑定方法 handleStoreChange 来处理 Redux 返回回来的数据
this.handleStoreChange = this.handleStoreChange.bind(this);
store.subscribe(this.handleStoreChange);
// 处理 handleAddItem 方法
this.handleAddItem = this.handleAddItem.bind(this);
// 处理 handleInputKeyUp 方法
this.handleInputKeyUp = this.handleInputKeyUp.bind(this);
}
render() {
return (
<div className="todo">
<div className="todo-title">
<h1>TodoList</h1>
</div>
{/* 使用 Input、Button 组件 */}
<div className="todo-action">
{/* Input 绑定 handleInputChange 事件 */}
{/* Input 绑定回车事件:handleInputKeyUp */}
<Input
placeholder='todo'
className="todo-input"
value={this.state.inputValue}
onChange={this.handleInputChange}
onKeyUp={this.handleInputKeyUp}
/>
{/* 为 Button 定义点击执行 handleAddItem 方法 */}
<Button
type="primary"
className="todo-submit"
onClick={this.handleAddItem}
>
提交
</Button>
</div>
{/* 使用 List 组件 */}
{/* 将原先的 data 换成 state 中的 todoList */}
{/* 列表点击事件绑定 handleDeleteItem 方法 */}
<div className="todo-list">
<List
size="large"
bordered
dataSource={this.state.todoList}
renderItem={(item, index) => (
<List.Item onClick={this.handleDeleteItem.bind(this, index)}>{index + 1} - {item}</List.Item>
)}
/>
</div>
</div>
);
}
// 编写 handleInputChange 方法
handleInputChange(e) {
// 通过 dispatch(action),将数据传递给 store
// 3. 使用 actionTypes
const action = {
type: CHANGE_INPUT_VALUE,
value: e.target.value
}
store.dispatch(action);
}
// 在 handleStoreChange 中处理数据
handleStoreChange() {
this.setState(store.getState());
}
// 编写 handleAddItem 方法
handleAddItem() {
// 通过 dispatch(action),将数据传递给 store
// 3. 使用 actionTypes
const action = {
type: ADD_TODO_ITEM
}
store.dispatch(action);
}
// 为 Input 的 keyUp 方法 handleInputKeyUp 绑定 handleAddItem
handleInputKeyUp(e) {
if(e.keyCode === 13) {
this.handleAddItem();
}
}
// 编写 handleDeleteItem 方法
handleDeleteItem(index) {
console.log(index);
// 通过 dispatch(action),将数据传递给 store
// 3. 使用 actionTypes
const action = {
type: DELETE_TODO_ITEM,
index
}
store.dispatch(action);
}
}
export default TodoList;
src/store/reducer.js
Сведения о коде
import { CHANGE_INPUT_VALUE, ADD_TODO_ITEM, DELETE_TODO_ITEM } from './actionTypes'; // 2. 引用 actionTypes
// 定义一个数据 defaultState
const defaultState = {
inputValue: '',
todoList: [
// '这是非常非常非常长的让人觉得不可思议的但是它语句通顺的第一条 TodoList',
// '这是非常非常非常长的让人觉得不可思议的但是它语句通顺的第二条 TodoList',
// '这是非常非常非常长的让人觉得不可思议的但是它语句通顺的第三条 TodoList',
// '这是非常非常非常长的让人觉得不可思议的但是它语句通顺的第四条 TodoList',
]
}
// 将数据 defaultState 最终以 state 形式导出去
export default (state = defaultState, action) => {
// 打印 state 和 action
// console.log(state);
// console.log(action);
// 在 reducer.js 中获取数据,并 return 回去处理结果
// 3. 使用 actionTypes
if(action.type === CHANGE_INPUT_VALUE) {
const newState = JSON.parse(JSON.stringify(state));
newState.inputValue = action.value;
return newState;
}
// 在 reducer.js 中获取数据,并 return 回去处理结果
// 3. 使用 actionTypes
if(action.type === ADD_TODO_ITEM) {
const newState = JSON.parse(JSON.stringify(state));
newState.todoList.push(newState.inputValue);
newState.inputValue = '';
return newState;
}
// 在 reducer.js 中获取数据,并 return 回去处理结果
// 3. 使用 actionTypes
if(action.type === DELETE_TODO_ITEM) {
const newState = JSON.parse(JSON.stringify(state));
newState.todoList.splice(action.index, 1);
return newState;
}
return state;
}
Кроме того, смысл извлечения actionTypes.js заключается в том, чтобы исправить значение action.type, чтобы он не сообщал об ошибке, потому что он используется в двух разных местах.
Девять оптимизаций: извлечь все действие
По мере увеличения объема кода мы обнаруживаем, что комментарии постепенно увеличиваются, поэтому здесь мы сначала удалим все комментарии и, пожалуйста, ознакомьтесь с потоком кода в предыдущих главах.
После очистки мы можем обнаружить, что хотя actionType извлекается, когда страница достаточно сложна, нашaction
Это все еще очень сложно в управлении, поэтому мы пытаемся поставить всеaction
извлекать.
Мы создаем новый actionCreators.js в каталоге магазина:
src/store/actionCreators.js
Сведения о коде
// 1. 引入 actionTypes
import { CHANGE_INPUT_VALUE, ADD_TODO_ITEM, DELETE_TODO_ITEM } from './actionTypes'
// 2. 导出相应 action
export const getInputChangeAction = (value) => ({
type: CHANGE_INPUT_VALUE,
value
})
export const getAddItemAction = () => ({
type: ADD_TODO_ITEM
})
export const getItemDeleteAction = (index) => ({
type: DELETE_TODO_ITEM,
index
})
Остроумные друзья, увидев это, вы должны понять наш замысел, поэтому давайте снова модифицируем TodoList.js:
src/TodoList.js
Сведения о коде
import React, { Component } from 'react';
import './index.css';
import { Input, Button, List } from 'antd';
import 'antd/dist/antd.css';
import store from './store';
import { getChangeInputValue, getAddTodoItem, getDeleteTodoItem } from './store/actionCreators'; // 3. 引入 actionCreators
class TodoList extends Component {
constructor(props) {
super(props);
this.state = store.getState();
this.handleInputChange = this.handleInputChange.bind(this);
this.handleStoreChange = this.handleStoreChange.bind(this);
store.subscribe(this.handleStoreChange);
this.handleAddItem = this.handleAddItem.bind(this);
this.handleInputKeyUp = this.handleInputKeyUp.bind(this);
}
render() {
return (
<div className="todo">
<div className="todo-title">
<h1>TodoList</h1>
</div>
<div className="todo-action">
<Input
placeholder='todo'
className="todo-input"
value={this.state.inputValue}
onChange={this.handleInputChange}
onKeyUp={this.handleInputKeyUp}
/>
<Button
type="primary"
className="todo-submit"
onClick={this.handleAddItem}
>
提交
</Button>
</div>
<div className="todo-list">
<List
size="large"
bordered
dataSource={this.state.todoList}
renderItem={(item, index) => (
<List.Item onClick={this.handleDeleteItem.bind(this, index)}>{index + 1} - {item}</List.Item>
)}
/>
</div>
</div>
);
}
handleInputChange(e) {
// 4. 使用 actionCreators 中的 getChangeInputValue
const action = getChangeInputValue(e.target.value);
store.dispatch(action);
}
handleStoreChange() {
this.setState(store.getState());
}
handleAddItem() {
// 4. 使用 actionCreators 中的 getAddTodoItem
const action = getAddTodoItem();
store.dispatch(action);
}
handleInputKeyUp(e) {
if(e.keyCode === 13) {
this.handleAddItem();
}
}
handleDeleteItem(index) {
// 4. 使用 actionCreators 中的 getAddTodoItem
const action = getDeleteTodoItem(index);
store.dispatch(action);
}
}
export default TodoList;
Таким образом, мы помещаем весьaction
Извлеченный, в больших проектах, он будет очень удобен для нашей работы.
Десять оптимизаций: компоненты пользовательского интерфейса и компоненты-контейнеры
Теперь сначала бросьте два определения:
- Компоненты пользовательского интерфейса - обманывайте компоненты, выполняйте рендеринг страницы
- Компоненты-контейнеры — смарт-компоненты, выполняющие логику страницы
Не будем много объяснять, сделаем разбиение кода, а потом объясним, почему есть эти два определения.
Здесь мы разделяем компоненты:
src/TodoList.js
Сведения о коде
import React, { Component } from 'react';
import './index.css';
import 'antd/dist/antd.css';
import store from './store';
import { getChangeInputValue, getAddTodoItem, getDeleteTodoItem } from './store/actionCreators';
// 1. 将 Input 等 antd 的组件引入迁移到 TodoListUI,并引入 TodoListUI
import TodoListUI from './TodoListUI';
class TodoList extends Component {
constructor(props) {
super(props);
this.state = store.getState();
this.handleInputChange = this.handleInputChange.bind(this);
this.handleAddItem = this.handleAddItem.bind(this);
this.handleInputKeyUp = this.handleInputKeyUp.bind(this);
this.handleDeleteItem = this.handleDeleteItem.bind(this);
this.handleStoreChange = this.handleStoreChange.bind(this);
store.subscribe(this.handleStoreChange);
}
render() {
return (
// 2. 编写 TodoListUI,传递参数到 TodoListUI 中
<TodoListUI
inputValue={this.state.inputValue}
todoList={this.state.todoList}
handleInputChange={this.handleInputChange}
handleInputKeyUp={this.handleInputKeyUp}
handleAddItem={this.handleAddItem}
handleDeleteItem={this.handleDeleteItem}
/>
);
}
handleInputChange(e) {
// 解决 Antd 中的 bug
e.persist();
const action = getChangeInputValue(e.target.value);
store.dispatch(action);
}
handleStoreChange() {
this.setState(store.getState());
}
handleAddItem() {
const action = getAddTodoItem();
store.dispatch(action);
}
handleInputKeyUp(e) {
// 解决 Antd 中的 bug
e.persist();
if(e.keyCode === 13) {
this.handleAddItem();
}
}
handleDeleteItem(index) {
// 解决 Antd 中的 bug
index.persist();
const action = getDeleteTodoItem(index);
store.dispatch(action);
}
}
export default TodoList;
Здесь мы извлекаем содержимое в рендере в подкомпонент, который находится в каталоге src, называемый TodoListUI, мы используем TodoList.js в качестве компонента-контейнера, просто передаем данные в TodoListUI, а затем пишем содержимое компонента пользовательского интерфейса. :
src/TodoListUI.js
Сведения о коде
// 3. 引入 Input 等组件
import React, { Component } from 'react';
import { Input, Button, List } from 'antd';
class TodoListUI extends Component {
render() {
return (
// 4. 接收 TodoList.js 中传递的数据
<div className="todo">
<div className="todo-title">
<h1>TodoList</h1>
</div>
<div className="todo-action">
<Input
placeholder='todo'
className="todo-input"
value={this.props.inputValue}
onChange={this.props.handleInputChange}
onKeyUp={this.props.handleInputKeyUp}
/>
<Button
type="primary"
className="todo-submit"
onClick={this.props.handleAddItem}
>
提交
</Button>
</div>
<div className="todo-list">
{/* 5. 在处理 handleDeleteItem 的时候需要注意,index 的值需要再进行处理 */}
<List
size="large"
bordered
dataSource={this.props.todoList}
renderItem={(item, index) => (
<List.Item onClick={() => {this.props.handleDeleteItem(index)}}>
{index + 1} - {item}
</List.Item>
)}
/>
</div>
</div>
);
}
}
export default TodoListUI;
Таким образом, мы завершили разделение компонентов пользовательского интерфейса и компонентов-контейнеров.
Что мы делаем:
- Перенесите и другие компоненты, такие как Input, в TodoListUI и внедрите TodoListUI.
- Напишите TodoListUI и передайте параметры в TodoListUI
- Внедрение таких компонентов, как ввод
- Получить данные, переданные в TodoList.js
- При обработке handleDeleteItem нужно обратить внимание на то, что значение индекса нужно обрабатывать заново
Таким образом, мы завершили извлечение страниц, когда у нас будет слишком много страниц, мы разделим контент на компоненты пользовательского интерфейса. С другой стороны, компоненты-контейнеры могут содержать бесконечное количество компонентов пользовательского интерфейса. так:
Компонент-контейнер — это умный компонент, который управляет всем; в то время как компонент пользовательского интерфейса — это компонент-дурак, ему нужно только выполнить событие, переданное компонентом-контейнером, и отобразить страницу.
Одиннадцать оптимизаций: компоненты без сохранения состояния
Когда компонент имеет только функцию render() и больше ничего, мы называем его компонентом без состояния.
В проекте TodoList наш TodoListUI работает только с render(), поэтому мы можем использовать TodoListUI как компонент без состояния:
src/TodoListUI
Сведения о коде
// 1. 我们不需要 react 中的 Component 了
import React from 'react';
import { Input, Button, List } from 'antd';
// class TodoListUI extends Component {
// 2. 进行无状态组件定义,然后父组件传递过来的数据,通过 props 获取
const TodoListUI = (props) => {
// 3. 我们不需要进行 render 了,直接 return 就可以了
return (
// 4. 接收 TodoList.js 中传递的数据
<div className="todo">
<div className="todo-title">
<h1>TodoList</h1>
</div>
<div className="todo-action">
{/* 5. 我们修改 this.props 为 props */}
<Input
placeholder='todo'
className="todo-input"
value={props.inputValue}
onChange={props.handleInputChange}
onKeyUp={props.handleInputKeyUp}
/>
<Button
type="primary"
className="todo-submit"
onClick={props.handleAddItem}
>
提交
</Button>
</div>
<div className="todo-list">
<List
size="large"
bordered
dataSource={props.todoList}
renderItem={(item, index) => (
<List.Item onClick={() => {props.handleDeleteItem(index)}}>
{index + 1} - {item}
</List.Item>
)}
/>
</div>
</div>
);
}
export default TodoListUI;
Здесь, как правило, мы делаем пять задач:
- Нам не нужно реагировать в
Component
, поэтому мы удалилиComponent
- Определите компонент без состояния, а затем данные, переданные родительским компонентом, будут получены через реквизиты.
- Нам больше не нужно рендерить, просто вернитесь напрямую
- Получить данные, переданные в TodoList.js
- Изменяем this.props на props
Twelve End: вызов Axios, Redux-Base завершена
Наконец дошли до финальной ссылки, нам нужно получить интерфейс предоставляемый бэкендом для дальнейшей разработки.
- Представляем Аксиос:
cnpm i axios -S
- существует
componentDidMount
Получите данные интерфейса из , выполните процесс и, наконец, отобразите его на странице:
TodoList.js
Сведения о коде
import React, { Component } from 'react';
import './index.css';
import 'antd/dist/antd.css';
import store from './store';
// 7. 从 actionCreators 中引入 initListAction
import { getChangeInputValue, getAddTodoItem, getDeleteTodoItem, initListAction } from './store/actionCreators';
import TodoListUI from './TodoListUI';
import axios from 'axios'; // 1. 引入 axios
class TodoList extends Component {
constructor(props) {
super(props);
this.state = store.getState();
this.handleInputChange = this.handleInputChange.bind(this);
this.handleAddItem = this.handleAddItem.bind(this);
this.handleInputKeyUp = this.handleInputKeyUp.bind(this);
this.handleDeleteItem = this.handleDeleteItem.bind(this);
this.handleStoreChange = this.handleStoreChange.bind(this);
store.subscribe(this.handleStoreChange);
}
render() {
return (
<TodoListUI
inputValue={this.state.inputValue}
todoList={this.state.todoList}
handleInputChange={this.handleInputChange}
handleInputKeyUp={this.handleInputKeyUp}
handleAddItem={this.handleAddItem}
handleDeleteItem={this.handleDeleteItem}
/>
);
}
// 2. 在 componentDidMount() 中进行 axios 接口调用
componentDidMount() {
axios.get('https://www.easy-mock.com/mock/5ca803587e5a246db3d100cb/todolist').then( (res) => {
console.log(res.data.todolist);
// 3. 将接口数据 dispatch 到 action 中,所以需要先前往 actionCreators.js 中创建 action
// 8. 创建 action 并 dispatch 到 reducer.js 中
const action = initListAction(res.data.todolist);
store.dispatch(action);
})
}
handleInputChange(e) {
// 解决 Antd 中的 bug
e.persist();
const action = getChangeInputValue(e.target.value);
store.dispatch(action);
}
handleStoreChange() {
this.setState(store.getState());
}
handleAddItem() {
const action = getAddTodoItem();
store.dispatch(action);
}
handleInputKeyUp(e) {
// 解决 Antd 中的 bug
e.persist();
if(e.keyCode === 13) {
this.handleAddItem();
}
}
handleDeleteItem(index) {
// 解决 Antd 中的 bug
index.persist();
const action = getDeleteTodoItem(index);
store.dispatch(action);
}
}
export default TodoList;
actionCreators.js
Сведения о коде
// 5. 从 actionTypes 引入 INIT_LIST_ACTION
import { CHANGE_INPUT_VALUE, ADD_TODO_ITEM, DELETE_TODO_ITEM, INIT_LIST_ACTION } from './actionTypes';
export const getChangeInputValue = (value) => ({
type: CHANGE_INPUT_VALUE,
value
})
export const getAddTodoItem = () => ({
type: ADD_TODO_ITEM
})
export const getDeleteTodoItem = (index) => ({
type: DELETE_TODO_ITEM,
index
})
// 4. 编写导出的 initListAction,所以需要先在 actionTypes 中引入 INIT_LIST_ACTION
export const initListAction = (data) => ({
type: INIT_LIST_ACTION,
data
})
actionTypes.js
Сведения о коде
export const CHANGE_INPUT_VALUE = 'change_input_value';
export const ADD_TODO_ITEM = 'add_todo_item';
export const DELETE_TODO_ITEM = 'delete_todo_item';
// 6. 导出 INIT_LIST_ACTION
export const INIT_LIST_ACTION = 'init_list_action';
reducer.js
Сведения о коде
// 9. 从 actionTypes 引用 INIT_LIST_ACTION
import { CHANGE_INPUT_VALUE, ADD_TODO_ITEM, DELETE_TODO_ITEM, INIT_LIST_ACTION } from './actionTypes';
const defaultState = {
inputValue: '',
todoList: []
}
export default (state = defaultState, action) => {
if(action.type === CHANGE_INPUT_VALUE) {
const newState = JSON.parse(JSON.stringify(state));
newState.inputValue = action.value;
return newState;
}
if(action.type === ADD_TODO_ITEM) {
const newState = JSON.parse(JSON.stringify(state));
newState.todoList.push(newState.inputValue);
newState.inputValue = '';
return newState;
}
if(action.type === DELETE_TODO_ITEM) {
const newState = JSON.parse(JSON.stringify(state));
newState.todoList.splice(action.index, 1);
return newState;
}
// 10. 接受 TodoList 传递过来的数据,并进行处理与返回
if(action.type === INIT_LIST_ACTION) {
const newState = JSON.parse(JSON.stringify(state));
newState.todoList = action.data;
return newState;
}
return state;
}
Таким образом, мы завершили вызов axios, отрендерили его на странице и разобрались.Идея такова:
- TodoList.js — импорт
axios
- TodoList.js — в компонентеDidMount()
axios
вызов интерфейса - TodoList.js — данные интерфейса
dispatch
прибытьaction
, поэтому вам нужно сначала перейти к actionCreators.js, чтобы создатьaction
- actionCreators.js — написать экспортированный
initListAction
, поэтому его нужно сначала ввести в actionTypesINIT_LIST_ACTION
- actionCreators.js — импортировано из actionTypes
INIT_LIST_ACTION
- actionTypes.js — экспорт
INIT_LIST_ACTION
к действиюCreators - TodoList.js — импортировано из actionCreators
initListAction
- ToList.js - Создание
action
а такжеdispatch
в редуктор.js - редуктор.js — ссылка из actionTypes
INIT_LIST_ACTION
- редуктор.js - принять данные, переданные TodoList, обработать и вернуть
Таким образом, мы завершили вызов интерфейса, и страница выглядит следующим образом:
На данный момент мы завершили Redux-Base.
Однако это просто простое использование redux. Мы можем чувствовать, что просто используя redux по-прежнему сложно для проекта, поэтому нам нужно промежуточное программу Redux-Thunk и Redux-Saga. И, наконец, попробуйте использовать React-redux.
Тринадцать продвинутых: ПО промежуточного слоя Redux
- Что такое промежуточное программное обеспечение?
Middleware — это подключаемый модуль, организованный между кем и кем.
- Что такое промежуточное ПО Redux?
Посмотрите на картинку:
Как видно на рисунке выше, когда мы отправляем действие в хранилище через Dispatch, мы обращаемся к промежуточному программному обеспечению в Dispatch для обработки. Он инкапсулирует и обновляет Dispatch, так что мы можем использовать не только объекты в Dispatch, но и функции методов.
Таким образом, когда мы передаем объект в Dispatch, это ничем не отличается от нашего обычного использования избыточности. Однако когда мы передаем функцию в Dispatch, если мы используем Redux-Thunk или Redux-Saga, они обработают это, что позволит нам также вызвать функцию.
Поэтому, говоря простым языком, промежуточное ПО Redux — это пакетное обновление Dispatch.
Fourteen Advanced: промежуточное ПО Redux-Thunk для управления запросами ajax
В главе 12 мы сделали Ajax-запрос в TodoList, и это нормально.
Однако с увеличением количества запросов Ajax, если мы все напишем на странице, страница будет выглядеть раздутой.
На данный момент необходим Redux-Thunk. Redux-Thunk может извлекать асинхронные запросы и сложную бизнес-логику в другие места для обработки.
Копируем копию кода Redux-Base в директорию Redux-Thunk и выполняем:
Примечание. Нет необходимости копировать папку node_modules.
- Установите зависимости:
npm i
- Запустите проект:
npm run start
Затем мы начинаем ссылаться на Redux-Thunk:
- Редукс Преобразователь:адрес гитхаба
- Установить:
npm i redux-thunk -S
- Учебный пример:
test.js
Сведения о коде
import { createStore, applyMiddleware } from 'redux';
import thunk from 'redux-thunk';
import rootReducer from './reducers/index';
const store = createStore(
rootReducer,
applyMiddleware(thunk)
)
Выглядит очень просто, есть лес, попробуем в проекте.
src/store/index.js
Сведения о коде
// 2. 从 redux 中引入 applyMiddleware,applyMiddleware 的作用是应用 redux 中间件
// 3. 引入 compose 函数,因为我们用到了两个中间件:redux-thunk 以及 redux-devtools-extension,需要 compose 辅助
import { createStore, applyMiddleware, compose } from 'redux';
import reducer from './reducer';
// 1. 从 redux-thunk 中引入 thunk
import thunk from 'redux-thunk';
// 3. 使用 redux-devtools-extension 中间件
const composeEnhancers = window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ ? window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__({}) : compose;
// 4. 使用 applyMiddleware 对此进行扩展
const enhancer = composeEnhancers(
applyMiddleware(thunk),
);
// 5. 在 createStore 进行 enhancer 调用
const store = createStore(
reducer,
enhancer
);
export default store;
Здесь мы делаем несколько вещей:
- от
redux-thunk
введен вthunk
- от
redux
введен вapplyMiddleware
,applyMiddleware
Роль заключается в применении нескольких промежуточных программ Redux. - представлять
compose
функцию, потому что мы используем два промежуточных ПО:redux-thunk
так же какredux-devtools-extension
,нужноcompose
Вспомогательный - использовать
redux-devtools-extension
промежуточное ПО - использовать
applyMiddleware
Расширение этого, т.е.redux-thunk
промежуточное ПО плюсredux-devtools-extension
промежуточное ПО - существует
createStore
провестиenhancer
передача
Таким образом, мы используем оба в одном проектеredux-thunk
промежуточное ПО плюсredux-devtools-extension
промежуточное ПО, которое делаетredux-thunk
цитаты.
Далее мы будем использоватьredux-thunk
охватывать
src/store/actionCreators.js
Сведения о коде
import { CHANGE_INPUT_VALUE, ADD_TODO_ITEM, DELETE_TODO_ITEM, INIT_LIST_ACTION } from './actionTypes';
// 1. 把 axios 从 TodoList.js 中剪切到 actionCreators.js 中
import axios from 'axios';
export const getChangeInputValue = (value) => ({
type: CHANGE_INPUT_VALUE,
value
})
export const getAddTodoItem = () => ({
type: ADD_TODO_ITEM
})
export const getDeleteTodoItem = (index) => ({
type: DELETE_TODO_ITEM,
index
})
export const initListAction = (data) => ({
type: INIT_LIST_ACTION,
data
})
// 2. 把 TodoList 文件中 componentDidMount() 的 axios.get() 挪到 actionCreators.js 中
// 3. 在没使用 redux-thunk 之前,我们仅可以在 actionCreators.js 中使用对象,现在我们也可以使用函数了。
export const getTodoList = () => {
// 7. 当我们使用 getTodoList 的时候,我们也能传递 store 的 dispatch,从而在下面代码中使用
return (dispatch) => {
axios.get('https://www.easy-mock.com/mock/5ca803587e5a246db3d100cb/todolist').then( (res) => {
// 8. 直接使用 actionCreators.js 中的 initListAction方法,并 dispatch 该 action
const action = initListAction(res.data.todolist);
dispatch(action);
})
}
}
src/TodoList.js
Сведения о коде
import React, { Component } from 'react';
import './index.css';
import 'antd/dist/antd.css';
import store from './store';
// 4. 在 TodoList.js 中引用 actionCreators.js 中的 getTodoList
import { getChangeInputValue, getAddTodoItem, getDeleteTodoItem, getTodoList } from './store/actionCreators';
import TodoListUI from './TodoListUI';
class TodoList extends Component {
constructor(props) {
super(props);
this.state = store.getState();
this.handleInputChange = this.handleInputChange.bind(this);
this.handleAddItem = this.handleAddItem.bind(this);
this.handleInputKeyUp = this.handleInputKeyUp.bind(this);
this.handleDeleteItem = this.handleDeleteItem.bind(this);
this.handleStoreChange = this.handleStoreChange.bind(this);
store.subscribe(this.handleStoreChange);
}
render() {
return (
<TodoListUI
inputValue={this.state.inputValue}
todoList={this.state.todoList}
handleInputChange={this.handleInputChange}
handleInputKeyUp={this.handleInputKeyUp}
handleAddItem={this.handleAddItem}
handleDeleteItem={this.handleDeleteItem}
/>
);
}
componentDidMount() {
// 5. 在 componentDidMount 中调用 getTodoList。如果我们没使用 redux-thunk,我们只能使用对象,但是现在我们可以使用函数了。
const action = getTodoList();
// 6. 当我们 dispatch 了 action 的时候,我们就调用了步骤 1 的 getTodoList(),从而获取了数据
store.dispatch(action);
}
handleInputChange(e) {
const action = getChangeInputValue(e.target.value);
store.dispatch(action);
}
handleStoreChange() {
this.setState(store.getState());
}
handleAddItem() {
const action = getAddTodoItem();
store.dispatch(action);
}
handleInputKeyUp(e) {
if(e.keyCode === 13) {
this.handleAddItem();
}
}
handleDeleteItem(index) {
const action = getDeleteTodoItem(index);
store.dispatch(action);
}
}
export default TodoList;
Увидев это, мы, возможно, были ошеломлены, поэтому давайте взглянем на идею:
- Пучок
axios
Вырезать из TodoList.js в actionCreators.js - Поместите TodoList в файл
componentDidMount()
изaxios.get()
Перейти к actionCreators.js - не используется
redux-thunk
Раньше мы могли использовать только объекты в actionCreators.js, теперь мы можем использовать и функции. - Ссылка на actionCreators.js в TodoList.js
getTodoList()
, и удалите те, на которые больше нет ссылокinitListAction
- существует
componentDidMount()
вызыватьgetTodoList()
. Если мы не используемredux-thunk
Мы можем использовать только объекты, но теперь мы можем использовать функции. - когда мы
dispatch
охватыватьaction
, мы называем шаг 1getTodoList()
, чтобы получить данные - когда мы используем
getTodoList()
, мы также можем пройтиstore
изdispatch
, который используется в следующем коде - Непосредственно используйте actionCreators.js в
initListAction
метод иdispatch
Долженaction
Таким образом, мы проходимredux-thunk
,Будуaxios
Вызовы интерфейса извлекаются в actionCreators.js.
Почему нам нужно пройти так много шагов, чтобы извлечь его из TodoList.js, который мы хорошо использовали изначально?
На самом деле, что нам нужно знать, так это то, что когда страница достаточно сложная, проект достаточно большой, а кода становится все больше и больше, если все вызовы нашего интерфейса находятся в компоненте-контейнере, нам неудобно управлять интерфейс, и, наконец, если нам нужно изменить определенный интерфейс, мы должны медленно найти его на странице.
пройти черезredux-thunk
call, мы извлекаем код интерфейса из компонента-контейнера, чтобы достичь: логика кода интерфейса — это логика кода интерфейса, а логика бизнес-кода — это логика бизнес-кода.
А такжеredux-thunk
Извлечение может облегчить наше автоматизированное тестирование. Мы, конечно, не знаем, как выглядит автоматизированное тестирование, но можем утешить себя тем, что оно всегда имеет смысл.
Резюме: На этом мы закончили справку и использование Redux-Thunk.Друзья могут попробовать больше и лучше познакомиться с Redux-Thunk.
Fifteen Advanced: промежуточное ПО Redux-Saga для управления запросами Ajax
Имея опыт работы с Redux-Thunk, мы также можем понять Redux-Saga.
Сначала мы все еще копируем файл из Redux-Base в каталог Redux-Saga.
Примечание. Нет необходимости копировать папку node_modules.
- Установите зависимости:
npm i
- Запустите проект:
npm run start
Затем мы начинаем ссылаться на Redux-Saga:
- Редукс Сага:адрес гитхаба
- Установить:
npm i redux-saga -S
- Учебный пример:
test.js
Сведения о коде
import { createStore, applyMiddleware } from 'redux'
import createSagaMiddleware from 'redux-saga'
import reducer from './reducers'
import mySaga from './sagas'
// create the saga middleware
const sagaMiddleware = createSagaMiddleware()
// mount it on the Store
const store = createStore(
reducer,
applyMiddleware(sagaMiddleware)
)
// then run the saga
sagaMiddleware.run(mySaga)
// render the application
Пуф, видно, что эталонный метод Redux-Saga такой же простой, как и у Redux-Thunk. Однако, пожалуйста, продолжайте учиться в форме, допускающей некоторую сложность.
Затем мы используем файл index.js в каталоге хранилища для ссылки на Redux-Saga:
src/store/index.js
Сведения о коде
// 1. 引入 applyMiddleware 和 compose 进行多个中间件的处理
import { createStore, applyMiddleware, compose } from 'redux';
import reducer from './reducer';
// 2. 引入 redux-saga 的 createSagaMiddleware
import createSagaMiddleware from 'redux-saga';
// 6. 创建并引用 store 下的 sagas.js 文件
import todoSaga from './sagas';
// 3. 调用 createSagaMiddleware 方法
const sagaMiddleware = createSagaMiddleware();
// 4. 定义 composeEnhancers
const composeEnhancers = window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ ? window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__({}) : compose;
// 5. 调用 composeEnhancers 进行多中间件处理
const enhancer = composeEnhancers(
applyMiddleware(sagaMiddleware),
);
const store = createStore(
reducer,
enhancer
);
// 7. 使用 todoSaga
sagaMiddleware.run(todoSaga);
export default store;
src/store/sagas.js
Сведения о коде
// 8. 使用 generator 函数定义 todoSaga
function* todoSaga() {
}
// 9. 将 generator 函数导出去
export default todoSaga;
Таким образом, мы завершили референс Redux-Saga и примерно сделали следующие шаги:
- представлять
applyMiddleware
а такжеcompose
Процесс множественное промежуточное ПО - представлять
redux-saga
изcreateSagaMiddleware
- передача
createSagaMiddleware
метод - определение
composeEnhancers
- передача
composeEnhancers
Разработка нескольких промежуточных программ - Создание и ссылка
store
файла sagas.js вtodoSaga
- пройти через
sagaMiddleware
использоватьtodoSaga
- использовать
generator
Файл определения функции sagas.js - Буду
generator
экспорт функции
При этом мы наблюдали за следующей страницей, и ошибки, говорящей о том, что мы цитировали правильно, не было.
Ниже мыcomponentDidMount()
в методеaxios.get()
Эти асинхронные интерфейсы для извлеченияsrc/store/sagas.js
обрабатывается в:
- src/TodoList.js
Сведения о коде
import React, { Component } from 'react';
import './index.css';
import 'antd/dist/antd.css';
import store from './store';
// 1. 删除 initListAction 以及下面的 axios,并引入 actionCreators.js 中的 getInitList
import { getChangeInputValue, getAddTodoItem, getDeleteTodoItem, getInitList } from './store/actionCreators';
import TodoListUI from './TodoListUI';
class TodoList extends Component {
constructor(props) {
super(props);
this.state = store.getState();
this.handleInputChange = this.handleInputChange.bind(this);
this.handleAddItem = this.handleAddItem.bind(this);
this.handleInputKeyUp = this.handleInputKeyUp.bind(this);
this.handleDeleteItem = this.handleDeleteItem.bind(this);
this.handleStoreChange = this.handleStoreChange.bind(this);
store.subscribe(this.handleStoreChange);
}
render() {
return (
<TodoListUI
inputValue={this.state.inputValue}
todoList={this.state.todoList}
handleInputChange={this.handleInputChange}
handleInputKeyUp={this.handleInputKeyUp}
handleAddItem={this.handleAddItem}
handleDeleteItem={this.handleDeleteItem}
/>
);
}
componentDidMount() {
// 5. 调用 getInitList,并使用 dispatch 将 action 派发出去。这时候不仅 reducer.js 可以接收到这个 action,我们的 sagas.js 也可以接收到这个 action。
const action = getInitList();
store.dispatch(action);
}
handleInputChange(e) {
const action = getChangeInputValue(e.target.value);
store.dispatch(action);
}
handleStoreChange() {
this.setState(store.getState());
}
handleAddItem() {
const action = getAddTodoItem();
store.dispatch(action);
}
handleInputKeyUp(e) {
if(e.keyCode === 13) {
this.handleAddItem();
}
}
handleDeleteItem(index) {
const action = getDeleteTodoItem(index);
store.dispatch(action);
}
}
export default TodoList;
- src/store/actionCreators.js
Сведения о коде
// 2. 导入 actionTypes.js 中的 GET_INIT_LIST
import { CHANGE_INPUT_VALUE, ADD_TODO_ITEM, DELETE_TODO_ITEM, INIT_LIST_ACTION, GET_INIT_LIST } from './actionTypes';
export const getChangeInputValue = (value) => ({
type: CHANGE_INPUT_VALUE,
value
})
export const getAddTodoItem = () => ({
type: ADD_TODO_ITEM
})
export const getDeleteTodoItem = (index) => ({
type: DELETE_TODO_ITEM,
index
})
export const initListAction = (data) => ({
type: INIT_LIST_ACTION,
data
})
// 3. 使用 GET_INIT_LIST
export const getInitList = () => ({
type: GET_INIT_LIST
});
- src/store/actionTypes.js
Сведения о коде
export const CHANGE_INPUT_VALUE = 'change_input_value';
export const ADD_TODO_ITEM = 'add_todo_item';
export const DELETE_TODO_ITEM = 'delete_todo_item';
export const INIT_LIST_ACTION = 'init_list_action';
// 4. 定义 GET_INIT_LIST 并导出给 actionTypes.js 使用
export const GET_INIT_LIST = 'get_init_list';
- src/store/sagas.js
Сведения о коде
// 6. 引用 redux-saga/effets 中的 takeEvery
// 13. 由于我们在 sagas.js 中没有引用到 store,所以不能使用 store.dispatch(),但是 redux-saga 给我们提供了 put 方法来代替 store.dispatch() 方法
import { takeEvery, put } from 'redux-saga/effects';
// 7. 引入 GET_INIT_LIST 类型
import { GET_INIT_LIST } from './actionTypes';
// 11. 将 TodoList.js 的 axios 引入迁移到 sagas.js 中
import axios from 'axios';
// 12. 引入 actionCreator.js 中的 initListAction
import { initListAction } from './actionCreators'
// 8. 使用 generator 函数
function* todoSaga() {
// 9. 这行代码表示,只要我们接收到 GET_INIT_LIST 的类型,我们就执行 getInitList 方法
yield takeEvery(GET_INIT_LIST, getInitList);
}
// 10. 定义 getInitList 方法
function* getInitList() {
try {
// 14. 在 sagas.js 中处理异步函数
const res = yield axios.get('https://www.easy-mock.com/mock/5ca803587e5a246db3d100cb/todolis');
const action = initListAction(res.data.todolist);
// 15. 等 action 处理完之后,在执行 put 方法
yield put(action);
} catch (error) {
console.log("接口请求失败,请检查 todolist 接口。");
}
}
export default todoSaga;
Таким образом мы извлекли функцию асинхронного запроса вызывающего интерфейса в файл sagas.js, в ходе чего сделали:
- TodoList.js — удалить
initListAction
и следующееaxios
и добавьте getInitList в actionCreators.js. - actionCreators.js — импортировать actionTypes.js
GET_INIT_LIST
- actionTypes.js — использовать
GET_INIT_LIST
- actionTypes.js — определение
GET_INIT_LIST
и экспортируйте в actionTypes.js для использования - TodoList.js — вызов
getInitList
и использоватьdispatch
Будуaction
отправлено. В настоящее время не только reducer.js может получить этоaction
, наш sagas.js также может получить этоaction
. - Цитировать
redux-saga/effets
серединаtakeEvery
- представлять
GET_INIT_LIST
Типы - использовать
generator
функция - пройти через
takeEvery
, указывая на то, что как только мы получимGET_INIT_LIST
тип, мы выполняемgetInitList
метод - определение
getInitList
метод - Поместите TodoList.js
axios
Представить миграцию на sagas.js - Импортировано в actionCreator.js
initListAction
- Так как мы не ссылались на sagas.js
store
, поэтому нельзя использоватьstore.dispatch()
,ноredux-saga
предоставил намput
метод заменыstore.dispatch()
метод, поэтому мы цитируемput
метод. - Обработка асинхронных функций в sagas.js
- Ждать
action
После обработки выполнитьput
метод:yield put(action)
Таким образом, мы успешно извлекли интерфейс асинхронного запроса из TodoList в sagas.js, чтобы обеспечить единообразное управление интерфейсом.
существует
src/store/sagas.js
, мы тоже проходимtry...catch...
метод для обработки интерфейса.Если интерфейс не существует или запрос ненормальный, мы будем знать, что интерфейс имеет ошибку.
Резюме: На этом мы закончили справку и использование Redux-Saga. Друзья могут попробовать больше и лучше познакомиться с Redux-Saga.
- использованная литература:генератор - Ляо Сюэфэн
Шестнадцать продвинутых: React-Redux
В предыдущих главах мы использовали React, также использовали Redux и коснулись промежуточного ПО Redux: Redux-Thunk и Redux-Saga.
Итак, в этой главе объясняется React-Redux.
- Что такое React-Redux.
Это сторонний модуль, который упрощает нам использование Redux в React.
Здесь, поскольку каталог React-Base отделен от React и Redux, мы копируем копию базового кода каталога Simplify в каталог React-Redux и модифицируем TodoList, чтобы начать наше путешествие React-Redux.
Метод преобразования Simplify в TodoList может относиться кГлава 3 Проект инициализации,Глава 4 Использование Ant Designтак же какГлава 5 Использование Redux.
подjsliangОпубликуйте свой собственный код после инициализации:
- src/index.js
Сведения о коде
import React from 'react';
import ReactDOM from 'react-dom';
import TodoList from './TodoList';
ReactDOM.render(<TodoList />, document.getElementById('root'));
- src/TodoList.js
Сведения о коде
import React, { Component } from 'react';
import './index.css';
import { Input, Button, List } from 'antd';
import 'antd/dist/antd.css';
import store from './store';
class TodoList extends Component {
constructor(props) {
super(props);
this.state = store.getState();
}
render() {
return (
<div className="todo">
<div className="todo-title">
<h1>TodoList</h1>
</div>
<div className="todo-action">
<Input placeholder='todo' className="todo-input" />
<Button type="primary" className="todo-submit">提交</Button>
</div>
<div className="todo-list">
<List
size="large"
bordered
dataSource={this.state.list}
renderItem={(item, index) => (<List.Item>{index + 1} - {item}</List.Item>)}
/>
</div>
</div>
);
}
}
export default TodoList;
- src/index.css
Сведения о коде
.todo {
width: 1000px;
margin: 20px auto 0;
padding: 30px;
border: 1px solid #ccc;
border-radius: 10px;
}
.todo-title {
text-align: center;
}
.todo-action .todo-input {
width: 200px;
}
.todo-action .todo-submit {
margin-left: 10px;
}
.todo-list {
margin-top: 30px;
}
- src/store/index.js
Сведения о коде
import { createStore } from 'redux';
import reducer from './reducer';
const store = createStore(reducer);
export default store;
- src/store/reducer.js
Сведения о коде
const defaultState = {
inputValue: '',
list: [
'这是非常非常非常长的让人觉得不可思议的但是它语句通顺的第一条 TodoList',
'这是非常非常非常长的让人觉得不可思议的但是它语句通顺的第二条 TodoList',
'这是非常非常非常长的让人觉得不可思议的但是它语句通顺的第三条 TodoList',
'这是非常非常非常长的让人觉得不可思议的但是它语句通顺的第四条 TodoList',
]
}
export default (state = defaultState, action) => {
return state;
}
В этот момент страница отображается как последняя страница главы 4:
- Реагировать Редукс:Адрес GitHub
- Установить
react-redux
:npm i react-redux -S
Пришло время показать настоящую технологию!
мы вsrc/index.js
цитируется вreact-redux
:
src/index.js
Сведения о коде
import React from 'react';
import ReactDOM from 'react-dom';
import TodoList from './TodoList';
// 1. 引入 react-redux 的 Provider
import { Provider } from 'react-redux';
// 3. 引入 store
import store from './store';
// 2. 使用 Provider 重新定义 App
const App = (
// 4. Provider 连接了 store,那么 Provider 里面的组件,都可以获取和使用 store 中的内容
<Provider store={store}>
<TodoList />
</Provider>
)
// 5. 直接渲染 App
ReactDOM.render(App, document.getElementById('root'));
Тогда можетsrc/TodoList.js
используется в:
src/TodoList.js
Сведения о коде
import React, { Component } from 'react';
import './index.css';
import { Input, Button, List } from 'antd';
import 'antd/dist/antd.css';
// 6. 在 TodoList 中,我们就不需要使用 import store from store 以及定义 constructor 获取 store 了,而是通过 react-redux 的 connect 来获取
import { connect } from 'react-redux';
class TodoList extends Component {
render() {
return (
<div className="todo">
<div className="todo-title">
<h1>TodoList</h1>
</div>
<div className="todo-action">
{/* 10. 使用 inputValue */}
<Input
placeholder='todo'
className="todo-input"
value={this.props.inputValue}
/>
<Button type="primary" className="todo-submit">提交</Button>
</div>
<div className="todo-list">
{/* 12. 使用 list */}
<List
size="large"
bordered
dataSource={this.props.list}
renderItem={(item, index) => (<List.Item>{index + 1} - {item}</List.Item>)}
/>
</div>
</div>
);
}
}
// 8. 定义 mapStateToProps 方法,把 store 里面的数据,映射成组件里面的 props,其中参数 state 就是 store 里面的数据
const mapStateToProps = (state) => {
return {
// 9. 定义 inputValue
inputValue: state.inputValue,
// 11. 定义 list
list: state.list
}
}
// 7. 导出 connect 方法,让 TodoList 和 store 做连接,需要对应两个规则,即:mapStateToProps 和
export default connect(mapStateToProps, null)(TodoList);
Теперь, когда мы обнаружили, что код все еще работает правильно, давайте проанализируем, какие шаги мы сделали:
- представлять
react-redux
изProvider
- использовать
Provider
переопределитьApp
- представлять
store
-
Provider
связаныstore
,ТакProvider
Компоненты внутри можно получить и использоватьstore
содержание в - прямой рендеринг
App
- В TodoList.js нам не нужно использовать
import store from store
и определениеconstructor
Получатьstore
, но черезreact-redux
изconnect
получить - экспорт
connect
метод, пусть TodoList.js иstore
Для подключения нужно соответствовать двум правилам, а именно:mapStateToProps
а также ** - определение
mapStateToProps
метод, поставитьstore
Данные в нем сопоставляются с данными в компонентеprops
, где параметрstate
то естьstore
данные внутри - определение
inputValue
- использовать
inputValue
- определение
list
- использовать
list
Итак, мы закончилиstore
пройти черезreact-redux
существуетTodoList.js
цитаты в.
Давайте попробуем изменитьstore
Значение:
src/TodoList.js
Сведения о коде
import React, { Component } from 'react';
import './index.css';
import { Input, Button, List } from 'antd';
import 'antd/dist/antd.css';
import { connect } from 'react-redux';
class TodoList extends Component {
render() {
return (
<div className="todo">
<div className="todo-title">
<h1>TodoList</h1>
</div>
<div className="todo-action">
{/* 3. 给 Input 绑定 onChange 事件 handleInputChange,此时我们通过 this.props 来绑定方法 */}
<Input
placeholder='todo'
className="todo-input"
value={this.props.inputValue}
onChange={this.props.handleInputChange}
/>
<Button type="primary" className="todo-submit">提交</Button>
</div>
<div className="todo-list">
<List
size="large"
bordered
dataSource={this.props.list}
renderItem={(item, index) => (<List.Item>{index + 1} - {item}</List.Item>)}
/>
</div>
</div>
);
}
}
const mapStateToProps = (state) => {
return {
inputValue: state.inputValue,
list: state.list
}
}
// 2. 定义 mapDispatchToProps 方法,该方法即是 TodoList.js 将 store.dispatch 方法映射到 props 上,所以我们就可以通过 this.props 来定义方法
// 4. 这里我们传递了 dispatch,所以就可以使用 store.dispatch 方法
const mapDispatchToProps = (dispatch) => {
return {
// 5. 定义 handleInputChange 方法
handleInputChange(e) {
const action = {
type: 'change_input_value',
value: e.target.value
}
// 6. 将 action 派发到 reducer.js
dispatch(action);
}
}
}
// 1. 使用 mapDispatchToProps 方法
export default connect(mapStateToProps, mapDispatchToProps)(TodoList);
изменениеsrc/reducer.js
:
src/reducer.js
Сведения о коде
const defaultState = {
inputValue: '',
list: [
'这是非常非常非常长的让人觉得不可思议的但是它语句通顺的第一条 TodoList',
'这是非常非常非常长的让人觉得不可思议的但是它语句通顺的第二条 TodoList',
'这是非常非常非常长的让人觉得不可思议的但是它语句通顺的第三条 TodoList',
'这是非常非常非常长的让人觉得不可思议的但是它语句通顺的第四条 TodoList',
]
}
export default (state = defaultState, action) => {
// 7. 判断传递过来的 action.type 是哪个,进行深拷贝,获取 action.value 的值,并返回 newState
if(action.type === 'change_input_value') {
const newState = JSON.parse(JSON.stringify(state));
newState.inputValue = action.value;
return newState;
}
return state;
}
На этот раз мы сделали 7 шагов:
- Используется в TodoList.js
mapDispatchToProps
метод - определение
mapDispatchToProps
метод, в котором TodoList.js будетstore.dispatch
метод сопоставляется сprops
, так что мы можем пройтиthis.props
Чтобы определить методы - Дать
Input
связыватьonChange
мероприятиеhandleInputChange
В это время мы прошлиthis.props
связать метод - существует
mapDispatchToProps
в котором мы прошлиdispatch
, так что вы можете использоватьstore.dispatch
метод - определение
handleInputChange
метод - Буду
action
отправить в редуктор.js - решение вынесено
action.type
Что это, сделать глубокую копию, получитьaction.value
стоимость и возвратnewState
На этом этапе мы кратко рассмотрели использование React-Redux, Ниже наша кнопка «Кнопка» нажимает кнопку «Отправить» и нажимает элемент «Элемент» для TodoList.list
Мы не будем подробно объяснять функцию удаления товара, заинтересованные партнеры могут реализовать ее самостоятельно и скачать, скачавjsliangкод для справки:
17 Резюме
Теперь, когда мы выполнили все пункты знаний, код и пояснения, пришло время расслабиться и поговорить: что мы узнали в этой статье:
- Использование муравьиного дизайна
- Введение и использование Redux
- Компоненты пользовательского интерфейса, компоненты-контейнеры, компоненты без сохранения состояния, а также извлечение и упаковка кода для некоторых крупных проектов.
- Использование Axios в React
- Чтобы упростить управление кодом интерфейса Axios, мы используем промежуточное ПО Redux Redux-Thunk и Redux-Thunk.
- Использование React-Redux Повторите использование Redux и изучите использование React-Redux.
На данный момент мы успешно завершили эту статью и перешли к следующему этапу обновления React.
Если ваши друзья чувствуютjsliangХорошо написано, не забудьте поставить [Нравится] или поставитьjsliangНажмите [звездочка] в библиотеке документации, ваш [Нравится] или [звездочка] — моя полная мотивация, ха-ха, увидимся в следующей части серии React!
jsliangРекламный толчок:
Может быть, друг хочет узнать об облачных серверах
Или друг хочет купить облачный сервер
Или маленькому партнеру необходимо обновить облачный сервер
Добро пожаловать, чтобы нажатьПродвижение облачного сервераПроверить!
библиотека документации jsliangЗависит отЛян ЦзюньронгиспользоватьCreative Commons Attribution-NonCommercial-ShareAlike 4.0 Международная лицензияЛицензия.
на основеGitHub.com/l ian Jun Ron…Создание работ выше.
Права на использование, отличные от разрешенных в настоящем Лицензионном соглашении, могут быть получены отCreative Commons.org/licenses/не…получено в.