当前位置: 首页 > 知识库问答 >
问题:

React redux更新嵌套数组的状态

王高邈
2023-03-14

我正在尝试学习React(使用redux),所以我正在制作一个应用程序,在其中我可以创建训练计划,将训练添加到计划中,然后将训练添加到训练中。

PlanListComponent

import { Button, Card, Typography } from "@material-ui/core/";
import { makeStyles } from "@material-ui/core/styles";
import DeleteIcon from "@material-ui/icons/Delete";
import React, { useEffect } from "react";
import { useDispatch, useSelector } from "react-redux";
import { deletePlan, getPlans } from "../actions/plansActions";
import AddWorkouts from "./AddWorkouts";

const useStyles = makeStyles((theme) => ({}));

function PlansList() {
  const classes = useStyles();

  const { plans } = useSelector((state) => state.plans);
  const dispatch = useDispatch();

  useEffect(() => {
    dispatch(getPlans());
  }, [dispatch]);

  return (
    <div>
      {plans.map((plan) => (
        <Card key={plan._id}>
          <Typography>{plan.name}</Typography>
          <Typography>{plan._id}</Typography>
          <div>
            {plan.workouts.map((workout) => (
              <li key={workout._id}>{workout.description}</li>
            ))}
          </div>
          <AddWorkouts plan={plan} />
          <Button onClick={() => dispatch(deletePlan(plan._id))}>
            <DeleteIcon /> Delete
          </Button>
        </Card>
      ))}
    </div>
  );
}

export default PlansList;

我的PlansList组件为每个计划呈现一张卡片。在这张卡片中,它为该计划中的每个训练呈现一个训练列表。将训练添加到计划后,“计划列表”组件不会重新渲染。添加的训练仅在我刷新页面后显示。我之所以选择这种情况,是因为我必须更新嵌套训练数组的状态,以便使React Reender成为我的组件。

这些是我在计划中添加训练的行动和简化方法。我在操作中发送的有效负载是一个对象数组。

行动

export const addWorkouts = (workouts, planId) => (dispatch, getState) => {
  axios
    .post(`/workouts/${planId}`, workouts, tokenConfig(getState))
    .then(res =>
      dispatch({
        type: ADD_WORKOUTS,
        id: planId
        payload: res.data
      }));
}

减速器

const initialState = {
  plans: [{
    workouts: []
  }],
  isLoading: false,
};

export default function (state = initialState, action) {
  switch (action.type) {
    case ADD_WORKOUTS:
      return {
        ...state,
        plans: {
          // guessing i should find the right plan by id here
          ...state.plans,
          workouts: {
            ...state.plans.workouts,
            workouts: state.plans.workouts.concat(action.payload)
          }
        }
      };
    default:
      return state;
  }

我看过很多关于如何更新嵌套数组状态的教程,并尝试了一些不同的方法,但我似乎在这里找不到正确的解决方案。

有人知道如何解决这个问题吗?

共有1个答案

习狐若
2023-03-14

您的减速机没有更新正确的内容。实际上,您正在将属性workouts作为数组转换为具有属性workouts作为数组的对象。这根本不是你想做的。

在redux中查找和更新数组元素并不麻烦,因为计划很容易成为一个由计划id键入的对象。计划的顺序重要吗?如果是这样的话,我仍然会保持计划由id键控,但是我会在状态中有一个单独的值,它存储计划id的有序数组。

我的建议如下:

const initialState = {
  plans: {}, // you could call this plansById
  isLoading: false,
  planOrder: [] // totally optional and only needed if the order matters when selecting all plans
};

export default function (state = initialState, action) {
  switch (action.type) {
    case ADD_WORKOUTS:
      const existingPlan = state.plans[action.id] || {};
      return {
        ...state,
        plans: {
          ...state.plans,
          [action.id]: {
            ...existingPlan,
            workouts: ( existingPlan.workouts || [] ).concat(action.payload)
          }
        }
      };
    default:
      return state;
  }

你可以把减速机拆成小块。如果您有多个更新计划的操作,您可以创建一个处理单个计划的减速器,这样您就不必重复所有的...东西多次。

function planReducer (planState = { workouts: []}, action ) {
  switch (action.type) {
    case ADD_WORKOUTS:
      return {
        ...planState,
        workouts: planState.workouts.concat(action.payload)
      };
      default:
        return planState;
    }
}

function rootReducer (state = initialState, action) {
  /**
   * you can use a `switch` statement and list all actions which modify an individual plan
   * or use an `if` statement and check for something, like if the action has a `planId` property 
   */
  switch (action.type) {
    case ADD_WORKOUTS:
    case OTHER_ACTION:
      return {
        ...state,
        plans: {
          ...state.plans,
          [action.id]: planReducer(state.plans[action.id], action),
        }
      };
    default:
      return state;
  }
}

使用建议的减缩器,您不需要对操作进行任何更改,但确实需要更改选择器,因为plans不再是数组。您的选择器变为(状态)=

如果存储了特定的计划订单,您将选择订单并从订单映射到各个计划:(状态)=

 类似资料:
  • 更新树结构中的嵌套组件时遇到问题。我创建了以下示例来说明这个问题:Codesandbox.io 为完整起见,这是正在嵌套的组件: 树中的节点在单击时应该是可选择的,我还希望在所有子节点中(递归地)切换所选状态。我想我可以通过将通过道具传递给孩子们来实现这一点,不幸的是,这似乎不起作用。 但是,子对象使用其旧状态重新呈现(可以理解,因为它们没有通过构造函数重新初始化)。正确的处理方法是什么? 我还尝

  • 问题内容: 我有以下mongodb文件结构: 我已经能够使用$ elemMatch来更新操作中的字段,但是当我尝试对参数执行相同的操作(修改)时,它似乎不起作用。我想知道我应该尝试哪种其他方法,以便能够成功更新特定参数中的字段(通过其pid查找)。 我当前拥有但不起作用的更新代码如下所示: 问题答案: MongoDB 3.6及更高版本 MongoDB3.6及更高版本提供了一项新功能,该功能允许您使

  • 这是我的架构:

  • 我正在尝试更新嵌套数组中的值,但无法使其工作。 我的对象是这样的 提前谢谢!

  • 我有以下架构 我想为创建静态方法,以便根据给定的更新 我的情况与建议的复制相似,但不相同,因为那里的家伙知道所有的,而我不知道。

  • 我正在使用平均堆栈在网格中显示以下数组。 嵌套数组: