减速器已更改状态,但未重新渲染

时间:2019-06-06 18:57:39

标签: reactjs typescript redux react-redux

这是我的减速器:

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.log(store.getState()));

并查看状态已更改,但组件未重新呈现。

1 个答案:

答案 0 :(得分:4)

问题在于您如何简化化简器中的状态。从此更改化简文件中的第24行

todoArr[index].isComplete = !todo.isComplete;

对此

todoArr[index] = {...todo, isComplete: !todo.isComplete};

基本上,您试图做的是直接更改状态对象,而不是创建新的对象签名。

您将要遇到的另一个问题是当前您正在创建具有相同ID的新待办事项。因此,当您完成一项时,所有项目都标记为已完成。取而代之的是,您可以仅使用当前时间戳作为唯一ID。

更改此

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);
相关问题