【问题标题】:Reducer changed state but does not re renderReducer 改变了状态但没有重新渲染
【发布时间】:2019-06-06 18:57:39
【问题描述】:

这是我的减速器:

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()));

看到状态改变了,但是组件没有重新渲染。

【问题讨论】:

  • 您没有在连接调用中传递 mapStateToProps。将undefined 更改为一个函数并将存储数据传递给您的组件......也就是const mapStateToProps = (state) =&gt; ({ ...state.todos })
  • 作为旁注,您实际上不需要 mapDispatch,connect 将调度传递给组件。你可以直接从那里发货。这样你就不需要在每次想要添加一个函数时都向调度映射添加一个函数:)
  • @JohnRuddell,sr 检查我的更新,来自ToDoItem 我从外部组件列表中得到todo
  • 好的,你在某个地方组合了减速器吗?您是否检查了 TodoList 组件中的 prop 值,您将在其中将状态映射到 props?
  • 只有一个减速器,没有组合。而且 TodoList 映射是正确的,我添加了项目并显示了该项目,但是当我更改字段 isComplete 时,它不起作用。

标签: reactjs typescript redux react-redux


【解决方案1】:

问题是如何在 reducer 中改变状态。从此更改减速器文件中的第 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);

【讨论】:

  • 这就是我想要的。谢谢@John Ruddell :)
  • @Khuong 随时!如果您需要更多帮助,请告诉我:)
猜你喜欢
  • 2019-09-23
  • 2019-11-19
  • 2018-12-31
  • 1970-01-01
  • 2018-12-31
  • 2018-02-27
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多