Вот мой редуктор:
export interface RootState {
todos: ToDo[];
}
const initialState = {
todos: []
};
export const todo = (
state: RootState = initialState,
action: Action
): RootState => {
switch (action.type) {
case TODO_ADD:
return {
todos: [...state.todos, action.payload.todo]
};
case TODO_TOGGLE_COMPLETE:
let todoArr = [...state.todos];
todoArr.forEach((todo: ToDo, index: number) => {
if (todo.id === action.payload.id) {
todoArr[index].isComplete = !todo.isComplete;
}
});
return {
todos: todoArr
};
default:
return state;
}
};
действие:
export const TODO_ADD = "TODO_ADD";
export const TODO_TOGGLE_COMPLETE = "TODO_TOGGLE_COMPLETE";
export interface Action {
type: string;
payload: any;
}
export interface ToDo {
id: string;
todo: string;
isComplete: boolean;
}
const add = (todo: ToDo): Action => ({
type: TODO_ADD,
payload: { todo }
});
export const toggleComplete = (id: string): Action => ({
type: TODO_TOGGLE_COMPLETE,
payload: { id }
});
export const addToDo = (todo: ToDo) => (dispatch: any) => {
dispatch(add(todo));
};
и мой компонент для вызова полного переключения:
import * as React from "react";
import { Button, Row, Col } from "antd";
import styled from "styled-components";
import { ToDo, toggleComplete } from "src/actions/todo";
import { connect } from "react-redux";
const mapDispatchToProps = (dispatch: any) => ({
toggleComplete: (id: string) => dispatch(toggleComplete(id))
});
type MapDispatchToProps = ReturnType<typeof mapDispatchToProps>;
type Props = MapDispatchToProps & {
todo: ToDo;
};
class TodoItem extends React.Component<Props> {
render() {
const { todo } = this.props;
return (
<Container>
<Col span = {20}>
<h3>{todo.todo}</h3>
</Col>
<Col span = {4}>
<Button
type = "primary"
onClick = {() => this.props.toggleComplete(this.props.todo.id)}
>
{todo.isComplete ? "Completed" : "Complete"}
</Button>
</Col>
</Container>
);
}
}
const Container = styled(Row)`
width: 100%;
`;
export default connect<undefined, MapDispatchToProps>(
undefined,
mapDispatchToProps
)(TodoItem);
todo получается из списка компонентов
import * as React from "react";
import { List } from "antd";
import styled from "styled-components";
import TodoItem from "./TodoItem";
import { connect } from "react-redux";
import { RootState } from "src/reducers/todo";
import { ToDo } from "src/actions/todo";
const mapStateToProps = (state: RootState) => ({
todos: state.todos
});
type StateProps = ReturnType<typeof mapStateToProps>;
class TodoList extends React.Component<StateProps> {
render() {
const { todos } = this.props;
return (
<Container>
<List
header = {
<div>
<h2>Todo List</h2>
<h4>
There are {todos.length} {todos.length === 1 ? "todo" : "todos"}
</h4>
</div>
}
bordered
dataSource = {todos}
renderItem = {(todo: ToDo) => (
<List.Item>
<TodoItem todo = {todo} />
</List.Item>
)}
/>
</Container>
);
}
}
const Container = styled.div`
width: 100%;
margin-top: 30px;
`;
export default connect(mapStateToProps)(TodoList);
Я уже реализовал подписку здесь:
store.subscribe(() => console.info(store.getState()));
и видите, что состояние изменилось, но компонент не перерисовывается.
в качестве побочного примечания вам на самом деле не нужно mapDispatch, подключение передает диспетчеризацию компоненту. Вы можете просто отправить прямо оттуда. Таким образом, вам не нужно добавлять функцию на карту отправки каждый раз, когда вы хотите добавить ее :)
@JohnRuddell, старший, проверьте мое обновление, от ToDoItem я получаю todo из списка компонентов снаружи
хорошо, вы где-то комбинируете редукторы? Вы проверили значения реквизита в компоненте TodoList, где вы сопоставляете состояние с реквизитом?
Только один редуктор, не комбинированный. И сопоставление TodoList правильное, я добавил элемент, и он показал этот элемент, но когда я меняю поле isComplete, он не работает.
@JohnRuddell, если вам нужен весь проект, я могу отправить вам :)
Это было бы полезно, ха-ха, я собирался настроить скрипку и много копипастить, лол
напишите свой адрес электронной почты или что-то здесь, я отправлю его вам
отправил, проверьте :)
Исправлено, дайте мне знать, если у вас есть еще проблемы :)





Проблема в том, как вы изменяете состояние в своем редукторе. Измените строку 24 в вашем файле редуктора с этого
todoArr[index].isComplete = !todo.isComplete;
к этому
todoArr[index] = {...todo, isComplete: !todo.isComplete};
по сути, то, что вы пытались сделать, это напрямую изменить объект состояния вместо создания новой подписи объекта.
Еще одна проблема, с которой вы столкнетесь, заключается в том, что в настоящее время вы создаете новые задачи с тем же идентификатором. Таким образом, все элементы помечаются как завершенные, когда вы завершаете один. Вместо этого вы можете просто использовать текущую метку времени в качестве уникального идентификатора.
Изменить это
const todo: ToDo = {
id: "1",
todo: value,
isComplete: false
};
this.props.addToDo(todo);
к этому
const todo: ToDo = {
id: `${new Date().valueOf()}`,
todo: value,
isComplete: false
};
this.props.addToDo(todo);
Это то, что я искал. Спасибо @Джон Радделл :)
@Khuong в любое время! Дай мне знать, если тебе еще понадобится помощь :)
вы не передаете mapStateToProps в своем вызове подключения. измените
undefinedна функцию и передайте данные хранилища вашему компоненту... например, что-то вродеconst mapStateToProps = (state) => ({ ...state.todos })