【问题标题】:Dispatching function does not "always" update the props调度功能不会“总是”更新道具
【发布时间】:2026-02-05 15:15:02
【问题描述】:

在我的示例待办事项列表应用程序中,我尝试在创建或删除一个待办事项后更新所有待办事项,以便在更改后重新呈现列表组件。它有时会更新待办事项,但有时不会。想不通原因。

我正在使用 Redux 和 Thunk。当一个按钮被点击时,我调度“创建请求”,然后发出异步请求,然后调度“创建接收”,然后调度fetchAllTodos(),然后捕获“创建失败”。

HomePage 容器中,我将this.props.todos 作为道具传递给TodoList 组件。我遇到的问题是它有时会使用更改重新呈现列表组件,但有时不会。我还在componentWillReceiveProps 方法中发现我没有得到更新的道具。这可能与服务器问题有关还是我做错了什么?

这是我设置商店的方式:

const middlewares = [thunk];

const store = createStore(
  combineReducers({
    ...reducers,
  }),
  compose(applyMiddleware(...middlewares))
);

这里是fetchAllTodos() 方法:

export function fetchAllTodos() {
  return dispatch => {
    dispatch({
      type: ALL_TODOS_REQUESTED
    });

    console.log('todos requested');

    return SuperFetch.get('/todos')
      .then(todos => {
        console.log('todos received ' + todos.length);
        dispatch({
          type: ALL_TODOS_RECEIVED,
          payload: todos
        })
      })
      .catch(error => dispatch({
        type: ALL_TODOS_FAILED,
        payload: error
      }));
  }

这里是createTodo()方法:

export function createTodo(description) {
  const body = {description: description};

  return dispatch => {
    dispatch({
      type: CREATE_TODO_REQUESTED
    });

    return SuperFetch.post(`/todos`, body)
      .then(todo => dispatch({
        type: CREATE_TODO_RECEIVED,
        payload: todo
      }))
      .then(dispatch(fetchAllTodos()))
      .catch(error => dispatch({
        type: CREATE_TODO_FAILED,
        payload: error
      }));
  }
}

这里是减速器:

export default function todoReducer(state = initialState, action) {
  switch (action.type) {
    case ALL_TODOS_REQUESTED:
      state = Object.assign({}, state, {todosLoading: true, todosError: null});
      break;
    case ALL_TODOS_RECEIVED:
      state = Object.assign({}, state, {todos: action.payload, todosLoading: false, todosError: null});
      break;
    case ALL_TODOS_FAILED:
      state = Object.assign({}, state, {todos: null, todosLoading: false, todosError: action.payload});
      break;
    // rest of it
  return state

HomePage 中,我只是将状态映射到道具,然后如果它们存在则传递待办事项:

render() {

    const {todos, error, loading} = this.props;

    // if error part

    if (todos && !loading) {
      return (
        <React.Fragment>
          <Container text>
            <TodoInput/>
          </Container>

          <Container style={{marginTop: '1em'}} text>
            <TodoList todos={todos}/>
          </Container>
        </React.Fragment>
      );
    }

问题可能与我在TodoInput 组件中调度操作并尝试更新TodoList 的事实有关吗?如果是这样,我该如何解决这个问题,因为我不想在同一个 HomePage 容器上调度所有操作。

【问题讨论】:

标签: reactjs redux react-redux redux-thunk


【解决方案1】:

问题在于您在 reducer 中管理状态的方式。您正在做的是直接改变现有状态,通过执行state = blah 这违反了redux-principles。为了让redux 有效地识别reducer 发生了变化,你必须return 一个全新的状态对象。只有这样,您连接的组件才会使用更新的 reducer 数据重新渲染。

export default function todoReducer(state = initialState, action) {
  switch (action.type) {
    case ALL_TODOS_REQUESTED:
      return {
        ...state,
        todosLoading: true,
        todosError: null
      }
    case ALL_TODOS_RECEIVED:
      return {
        ...state,
        todos: action.payload, 
        todosLoading: false, 
        todosError: null
      }
    case ALL_TODOS_FAILED:
      return {
        ...state,
        todos: null, 
        todosLoading: false, 
        todosError: action.payload
      }
    default:
       return state
  }
}

【讨论】:

  • 感谢更正和解释。我纠正了我的减速器,但仍然有同样的问题。我将尝试在 HomePage 容器中完成所有操作,看看它是否有效,但如果没有,我还有另一个我无法理解的问题。
【解决方案2】:

问题是如何更新减速器中的状态:

如果 todos 是对象

state = {...state, {todos: {...action.payload, ...state.todos }, todosLoading: false, todosError: null}}

如果待办事项是列表

state = {...state, {todos: state.todos.concat(action.payload) }, todosLoading: false, todosError: null}}

【讨论】: