【问题标题】:React Redux - update child in state arrayReact Redux - 更新状态数组中的子节点
【发布时间】:2017-07-22 03:41:07
【问题描述】:

所以我在 Redux 存储中有一个名为 currentAccount 的对象。它有一个名为groups 的子数组,它有一个名为tasks 的子数组。

现在,我可以通过或多或少地在 Angular 中真正轻松地更新一项任务:

function updateTask(task){
   http.post('xyz/updateTask', function(updatedTask){
        task = updatedTask;
   });
}

...这样就可以了。

在 React 中,我可以将数据发送到 actions,然后使用 Axios 将其发布到 API,但是……如何查找和更新旧任务?

我可以:

  • 让服务器再次返回整个currentAccount对象,然后转成JSON字符串再返回(强制Redux重新渲染整个树),
  • ...或者在 forEach 中执行 forEach 以通过其 ID 查找任务,然后替换它(虽然我不确定 Redux 是否会接受更改)

但这两个都让我觉得完全疯了。有没有更简单的方法,或者这只是 React 的工作方式?

抱歉,如果这是一个愚蠢的问题,我真的不知道该怎么说,哈哈。

【问题讨论】:

    标签: reactjs react-redux


    【解决方案1】:

    一旦您从 http 调用中获得响应,就派发一个更新商店的操作。您需要访问组件中的调度,因此您将使用 mapDispatchToProps 来提供功能。

    这里是创建者Dan Abramov 为Redux 编写的一个很棒的入门教程。

    此代码示例应该对您有所帮助。

    // I'm using this stateless functional component to
    // render the presentational view
    const Task = ({ label, info }) => (
        <div className="task">
            <h3{ label }</h3>
            <p{ info }</p>
        </div>
    );
    
    // this is the class that receives props from connect
    // and where we render our tasks from
    class Tasks extends PureComponent {
    
        // once your component is mounted, get your
        // http data and then disptach update action
        componentDidMount() {
            // using axios here but you can use any http library
            axios.post( "/some_url", task )
                .then( ( response ) => {
    
                    // get update provided by mapDispatchToProps
                    // and use it to update tasks with response.data
                    const { update } = this.props;
                    update( response.data );
                })
                .catch( ( error ) ) => {
                    // handle errors
                }
        }
    
        render() {
            // destructure tasks from props
            const { tasks } = this.props;
    
            // render tasks from tasks and pass along props
            // if there are no tasks in the store, return a loading indicator
            return (
                <div className="tasks">
                    {
                        tasks ? tasks.map(( task ) => {
                            return <Task
                                label={ task.label }
                                info={ task.info }
                            />
                        }) :
                        <div className="loading">Loading...</div>
                    }
                </div>
            );
        }
    }
    
    // this will provide the Tasks component with props.task
    const mapStateToProps = ( state ) => {
        return {
            tasks: state.tasks
        }
    }
    
    // this will provide the Tasks component with props.update
    const mapDispatchToProps = ( dispatch ) => {
        return {
            update: ( tasks ) => {
                dispatch({
                    type: "UPDATE_TASKS",
                    tasks
                });
            }
        }
    }
    
    // this connects Task to the store giving it props according to your
    // mapStateToProps and mapDispatchToProps functions
    export default Task = connect( mapStateToProps, mapDispatchToProps )( Task );
    

    您将需要一个处理"UPDATE_TASK" 操作的reducer。 reducer 更新 store,考虑到组件是连接的,它会收到更新后 store 值的新 props,并且任务会在 DOM 中更新。

    编辑:为了解决减速器,这里是一个额外的例子。

    import { combineReducers } from "redux";
    
    const tasks = ( state = [], action ) => {
      switch( action.type ) {
        case "UPDATE_TASKS":
          // this will make state.tasks = action.tasks which
          // you dispatched from your .then method of the http call
          return action.tasks;
        default:
          return state;
      }
    };
    
    const other = ( state = {}, action ) => {
      ...
    }
    
    const combinedReducers = combineReducers({
      tasks,
      other
    });
    
    const store = createStore(
        combinedReducers/*,
        persisted state,
        enhancers*/
    );    
    
    /*
    
      The above setup will produce an initial state tree as follows:
    
      {
        tasks: [ ],
        other: { }
      }
    
      After your http call, when you dispatch the action with the tasks in
      the response, your state would look like
    
      {
        tasks: [ ...tasks you updated ],
        other: { }
      }
    
    */
    

    【讨论】:

    • 感谢您的深入回答凯尔,但我认为您可能误解了我的问题?我没有问题映射任务,发送带有有效负载的操作或使用 Axios 发布,我只是不知道如何从减速器中查找和更新任务。
    【解决方案2】:

    如果其他人对此感到困惑,我想我已经解决了。

    我只是传递任务父母的所有索引,然后使用 'dotPoints' 设置状态如下:

    dotProp.set(state, `currentProject.groups.${action.groupIndex}.tasks.${action.taskIndex}`, action.task);
    

    到目前为止,这似乎是一个相当简洁的解决方案。

    【讨论】:

      猜你喜欢
      • 2021-04-02
      • 1970-01-01
      • 1970-01-01
      • 2017-09-22
      • 1970-01-01
      • 2019-05-30
      • 1970-01-01
      • 1970-01-01
      • 2019-06-13
      相关资源
      最近更新 更多