- Требования.
- Нормальный ? компоненты
- Проектирование хранилища и редуктора Redux
- redux/actionTypes
- редукс/действия
- addTodo
- toggleTodo
- setFilter
- редукторы/тодос
- Что делают редукторы?
- случай ADD_TODO
- случай TOGGLE_TODO
- по умолчанию
- Функция фильтра
- constants.ts
- reducers/visibilityFilters.js
- редукторы/индекс
- redux/selectors.js
- компоненты/TodoList
- AddTodo, Todo, VisibilityFilters,
- Резюме.
Требования.
https://react-redux.js.org/tutorials/connect#connecting-the-components
На этот раз мы будем использовать создателей действий, которые просто отправляют аргументы в paylaod, и
reducers, которые получают значения из полезной нагрузки и изменяют глобальное состояние в соответствии с перемещенными actionTypes.
Они четко разделены.
Нормальный ? компоненты
- AddTodo отправляет действия ADD_TODO из входа onChange
- TodoList рисует список todo и использует внутренние фильтры видимости (VisibilityFilters)
- Todo рисует один объект и отправляет действие, которое переключает статус выполненного или невыполненного объекта onClick
- ВидимостьФильтры фильтруют по всем, завершенным и незавершенным условиям. Они принимаются в качестве аргументов activeFilter, который отправляет setFilter.
Конструкция выглядит следующим образом
Проектирование хранилища и редуктора Redux
Поскольку сложно говорить о todo, давайте проследим за фактическим кодом.
redux/actionTypes
Создайте папку redux/ в src/ и поместите в нее
Создайте там файл actionTypes.ts.
export const ADD_TODO = "ADD_TODO";
export const TOGGLE_TODO = "TOGGLE_TODO";
export const SET_FILTER = "SET_FILTER";
Необходимыми действиями являются
- Добавление действия
- Переключение задачи (переключение между выполненной и невыполненной задачей)
- Установите фильтры для отображения списка дел.
Это три действия.
Поэтому мы определяем эти три параметра как константы в строке.
Это типы действий.
редукс/действия
Затем создайте действия, основанные на только что созданных типах действий
import { ADD_TODO, TOGGLE_TODO, SET_FILTER } from "./actionTypes";
Импортирование типов действий
Используйте эти строковые константы в качестве идентификаторов типов каждого действия.
addTodo
let nextTodoId = 0;
export const addTodo = content => ({
type: ADD_TODO,
payload: {
id: ++nextTodoId,
content
}
});
Инициализируйте следующий ID значением 0.
Возьмите содержание.
Поместите nextTodoId и полученный контент в paylaod
Установите значение nextTodoId равным +1
Установите тип ADD_TODO
Создайте действие под названием addTodo.
toggleTodo
export const toggleTodo = id => ({
type: TOGGLE_TODO,
payload: { id }
});
Возьмите идентификатор, передайте его в полезную нагрузку и установите
Добавьте TOGGLE_TODO к типу.
setFilter
export const setFilter = filter => ({ type: SET_FILTER, payload: { filter } });
Принимает фильтр, передает его в paylaod и устанавливает тип в
Установите тип на SET_FILTER
редукторы/тодос
Что делают редукторы?
https://react-redux.js.org/tutorials/connect#connecting-the-components
В главе Redux Store/Reducers в описании учебника говорится
Эти редукторы работают совместно с действиями ADD_TODO, TOGGLE_TODO и SET_FILTER.
Существует два типа объектов глобального состояния, которые хранятся.
- byIDs – это список TODO с содержанием
- allIds – это просто идентификатор списка TODO.
Объект allIds интерпретируется только как идентификатор списка TODO.
import { ADD_TODO, TOGGLE_TODO } from "../actionTypes";
Импортируйте константы для добавления задач и переключения задач из actionTypes.
const initialState = {
allIds: [],
byIds: {}
};
Определите массив всех идентификаторов и отдельных объектов ID в начальном состоянии.
Определите эти пустые.
Отсюда создается и поддерживается глобальное состояние.
export default function(state = initialState, action) {
switch (action.type) {
case ADD_TODO: {
//...
}
case TOGGLE_TODO: {
//...
}
default:
// ...
}
}
Функции этого модуля следующие
ADD_TODO, TOGGLE_TODO и по умолчанию, который действует как else
Определите эти
Действие просто отправляет тип и объект в полезную нагрузку.
Затем редуктор будет обрабатывать содержимое объекта.
случай ADD_TODO
В случае ADD_TODO
case ADD_TODO: {
const { id, content } = action.payload;
return {
...state,
allIds: [...state.allIds, id],
byIds: {
...state.byIds,
[id]: {
content,
completed: false
}
}
};
}
Разверните ID всех прошлых todos в allIds и добавьте текущий к переданному ID.
Добавьте идентификаторы, которые передаются в данный момент.
В byIds разверните todos в byIds.
В качестве ключа используется ID текущего переданного todo.
Добавить объект с переданным содержимым и завершить: false
и добавить объект с
Добавить текущую двойку к состоянию, содержащему текущие byIds и allIds.
Возвращение с возвращением.
Вот что произойдет при вызове ADD_TODO.
случай TOGGLE_TODO
case TOGGLE_TODO: {
const { id } = action.payload;
return {
...state,
byIds: {
...state.byIds,
[id]: {
...state.byIds[id],
completed: !state.byIds[id].completed
}
}
};
}
В случае TOGGLE_TODO
В отличие от случая ADD, где и id, и содержимое берутся из action.payload, в случае TOGGLE_TODO
Из action.payload извлекается только id.
Расширьте текущее состояние и добавьте к нему эти.
Разверните содержимое текущих byIds в byIds и добавьте их к нему.
Расширьте состояние текущего номера ID в byIds с аргументом ID в качестве ключа и добавьте к нему эти номера.
Отменяет True False завершенного аргумента ID.
по умолчанию
Если ни то, ни другое не происходит, и действие выполняется, оно интерпретируется как возвращение глобального состояния как оно есть.
Функция фильтра
- Добавление Todo
- Переключите “Выполнено”.
Подобно этим, изменения фильтра также создают редуктор в отдельном файле.
При изменении фильтра также создается редуктор в отдельном файле.
constants.ts
export const VISIBILITY_FILTERS = {
ALL: "all",
COMPLETED: "completed",
INCOMPLETE: "incomplete"
};
Определение констант фильтра дисплея. Это не требует объяснений.
reducers/visibilityFilters.js
import { SET_FILTER } from "../actionTypes";
import { VISIBILITY_FILTERS } from "../../constants";
Импортируйте константы SET_FILTER из первого созданного actionTypes.
Импортируйте константы VISIBILITY_FILTERS из констант, созданных непосредственно перед этим
Импортируйте объект константы VISIBILITY_FILTERS из констант, созданных непосредственно перед этим.
const initialState = VISIBILITY_FILTERS.ALL;
Установите начальное значение сохраняемого глобального состояния на все
const visibilityFilter = (state = initialState, action) => {
switch (action.type) {
case SET_FILTER: {
return action.payload.filter;
}
default: {
return state;
}
}
};
При вызове SET_FILTER происходит простой процесс, который возвращает значение фильтра, полученное из фильтра в action.payload, как оно есть.
Простой процесс, который возвращает полученное значение фильтра как есть.
export default visibilityFilter;
Затем экспортируйте. Это не требует объяснений.
Теперь все редукторы созданы.
редукторы/индекс
import { combineReducers } from "redux";
import visibilityFilter from "./visibilityFilter";
import todos from "./todos";
export default combineReducers({ todos, visibilityFilter });
Наконец, используйте combineReducers в reducers/index, чтобы
Наконец, используйте combineReducers в reducers/index для объединения редукторов. Теперь вы готовы к работе с магазином.
redux/selectors.js
Последний большой для редута. Их несколько.
Их несколько, но, похоже, используется только getTodosByVisibilityFilter.
import { VISIBILITY_FILTERS } from "../constants";
Импорт констант фильтра
export const getTodosByVisibilityFilter = (store, visibilityFilter) => {
const allTodos = getTodos(store);
switch (visibilityFilter) {
case VISIBILITY_FILTERS.COMPLETED:
return allTodos.filter(todo => todo.completed);
case VISIBILITY_FILTERS.INCOMPLETE:
return allTodos.filter(todo => !todo.completed);
case VISIBILITY_FILTERS.ALL:
default:
return allTodos;
}
};
Но это не так.
Используйте getTodos для импорта констант фильтров
export const getTodos = store =>
getTodoList(store).map(id => getTodoById(store, id));
getTodos использует getTodoList и getTodoById, которая является новой функцией, позволяющей пользователю создать список объектов todo.
export const getTodoList = store =>
getTodosState(store) ? getTodosState(store).allIds : [];
export const getTodoById = (store, id) =>
getTodosState(store) ? { ...getTodosState(store).byIds[id], id } : {};
getTodoList и getTodoById использовали getTodoState.
export const getTodosState = store => store.todos;
В итоге мы использовали весь файл.
компоненты/TodoList
В компоненте рисования TodoList селекторы
import { getTodosByVisibilityFilter } from "../redux/selectors";
const mapStateToProps = state => {
const { visibilityFilter } = state;
const todos = getTodosByVisibilityFilter(state, visibilityFilter);
return { todos };
}
Используйте getTodosByVisibilityFilter, используемый для вывода тодосов.
import { connect } from "react-redux";
export default connect(mapStateToProps)(TodoList);
Это связано с тем, что он может быть использован TodoList внутри того же файла.
TodoList внутри одного и того же файла.
import Todo from "./Todo";
const TodoList = ({ todos }) => (
<ul className="todo-list">
{todos && todos.length
? todos.map((todo, index) => {
return <Todo key={`todo-${todo.id}`} todo={todo} />;
})
: "No todos, yay!"}
</ul>
);
Здесь <Todo/>
может быть передан внутри
Todo – это данные, а Todo – это компонент для рисования.
Это довольно запутанно.
AddTodo, Todo, VisibilityFilters,
Они также используют connect для соединения данных и действий таким же образом.
import React from "react";
import { connect } from "react-redux";
import cx from "classnames";
import { toggleTodo } from "../redux/actions";
const Todo = ({ todo, toggleTodo }) => (
<li className="todo-item" onClick={() => toggleTodo(todo.id)}>
{todo && todo.completed ? "👌" : "👋"}{" "}
<span
className={cx(
"todo-item__text",
todo && todo.completed && "todo-item__text--completed"
)}
>
{todo.content}
</span>
</li>
);
// export default Todo;
export default connect(
null,
{ toggleTodo }
)(Todo);
import React from "react";
import { connect } from "react-redux";
import { addTodo } from "../redux/actions";
class AddTodo extends React.Component {
constructor(props) {
super(props);
this.state = { input: "" };
}
updateInput = input => {
this.setState({ input });
};
handleAddTodo = () => {
this.props.addTodo(this.state.input);
this.setState({ input: "" });
};
render() {
return (
<div>
<input
onChange={e => this.updateInput(e.target.value)}
value={this.state.input}
/>
<button className="add-todo" onClick={this.handleAddTodo}>
Add Todo
</button>
</div>
);
}
}
export default connect(
null,
{ addTodo }
)(AddTodo);
import React from "react";
import cx from "classnames";
import { connect } from "react-redux";
import { setFilter } from "../redux/actions";
import { VISIBILITY_FILTERS } from "../constants";
const VisibilityFilters = ({ activeFilter, setFilter }) => {
return (
<div className="visibility-filters">
{Object.keys(VISIBILITY_FILTERS).map(filterKey => {
const currentFilter = VISIBILITY_FILTERS[filterKey];
return (
<span
key={`visibility-filter-${currentFilter}`}
className={cx(
"filter",
currentFilter === activeFilter && "filter--active"
)}
onClick={() => {
setFilter(currentFilter);
}}
>
{currentFilter}
</span>
);
})}
</div>
);
};
const mapStateToProps = state => {
return { activeFilter: state.visibilityFilter };
};
// export default VisibilityFilters;
export default connect(
mapStateToProps,
{ setFilter }
)(VisibilityFilters);
Резюме.
Чтобы отделить логику Redux в приложении React Redux и соединить ее с помощью connect
Создайте карту одноименных переменных и строк для ADD_TODO, TOGGLE_TODO, SET_FILTER в redux/actionTypes.js
В redux/actions.js тип применяется из actionTypes, а аргумент помещается в объект в paylaod.
redux/reducers/todo.js
Создайте начальное состояние в redux/reducers/visibilityFilters.js
Создайте initialState в redux/reducers/visibilityFilters.js и используйте его в качестве первого состояния, а также используйте переключатели для передачи его каждому action.type.
Создайте кейс, который обновляет состояние на основе значения action.payload, переданного для каждого action.type.
Объедините их в redux/reducers/index.js с помощью combineReducers и выведите в виде модуля.
Импортируйте эти редукторы в redux/store.js, создайтеStore и снова выведите как модуль
Затем магазин связывается с провайдером в src/index.js и выводится как модуль.
Нарисуйте внутри компонент рисования под названием TodoApp.
В Components/TodoApp нарисуйте больше компонентов рисования под названием AddTodo, TodoList и VisibilityFilters
Components/TodoList использует mapToStateProps и connect для получения значений todo из getTodosByVisibilityFilter.
Фильтр getTodosByVisibilityFilter находится в redux/selectors.js
Тодо извлекается из хранилища в соответствии с фильтром видимости.
Components/TodoList затем расширяет todo в Components/Todo и передает его дальше.
В Components/Todo, когда есть todo.completed, рисуется горизонтальная линия или добавляется className для изменения пиктограммы.
Вот как происходит этот процесс.