我正在尝试学习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;
}
我看过很多关于如何更新嵌套数组状态的教程,并尝试了一些不同的方法,但我似乎在这里找不到正确的解决方案。
有人知道如何解决这个问题吗?
您的减速机没有更新正确的内容。实际上,您正在将属性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及更高版本提供了一项新功能,该功能允许您使
这是我的架构:
我正在尝试更新嵌套数组中的值,但无法使其工作。 我的对象是这样的 提前谢谢!
我有以下架构 我想为创建静态方法,以便根据给定的更新 我的情况与建议的复制相似,但不相同,因为那里的家伙知道所有的,而我不知道。
我正在使用平均堆栈在网格中显示以下数组。 嵌套数组: