Reactjs 反应:更改深度嵌套状态优化

Reactjs 反应:更改深度嵌套状态优化,reactjs,state,immutability,nested-datalist,Reactjs,State,Immutability,Nested Datalist,我提出了一个解决方案,可以在React中的第二级嵌套状态中更改属性,该状态不可伸缩,而且似乎效率不高。如何重构handleOnChange方法以更改reps和weight import React,{useState}来自“React”; 常量训练={ id:“123-234sdf-1213”, 名称:“工单名称”, 完成:错误, 练习:[ { 名称:“后蹲”, 设置:[ { 编号:0, 代表:0,, 重量:0,, 完成:错误, }, { 编号:1, 代表:0,, 重量:0,, 完成:错误, }

我提出了一个解决方案,可以在React中的第二级嵌套状态中更改属性,该状态不可伸缩,而且似乎效率不高。如何重构
handleOnChange
方法以更改
reps
weight

import React,{useState}来自“React”;
常量训练={
id:“123-234sdf-1213”,
名称:“工单名称”,
完成:错误,
练习:[
{
名称:“后蹲”,
设置:[
{
编号:0,
代表:0,,
重量:0,,
完成:错误,
},
{
编号:1,
代表:0,,
重量:0,,
完成:错误,
},
{
编号:2,
代表:0,,
重量:0,,
完成:错误,
},
],
},
{
名称:“腿部按压”,
设置:[
{
编号:0,
代表:0,,
重量:0,,
完成:错误,
},
{
编号:1,
代表:0,,
重量:0,,
完成:错误,
},
{
编号:2,
代表:0,,
重量:0,,
完成:错误,
},
],
},
],
};
导出默认函数App(){
const[workoutState,setWorkoutState]=使用状态(训练);
常量handleOnChange=(e,exIndex,setIndex)=>{
const value=e.target.value?parseFloat(e.target.value):“”;
const exercises=[…workoutState.exercises];
练习[exIndex]。设置[setIndex]={
…练习[exIndex]。设置[setIndex],
[e.target.name]:值,
};
设置工作状态({
…美国,
练习,
});
};
返回(
{workoutState.name}
{workoutState.exercises.map((ex,exIndex)=>(
{ex.name}
{ex.sets.map((set,setIndex)=>(
代表:{'}
handleOnChange(e,exIndex,setIndex)}
/>
重量:{'}
handleOnChange(e,exIndex,setIndex)}
/>
))}
))}
);
}

我想说,您希望如何更新嵌套状态,这是正确的,但您当前的
handleOnChange
实现中确实存在状态变异。您正在变异
练习[exIndex]

const handleOnChange = (e, exIndex, setIndex) => {
  const value = e.target.value ? parseFloat(e.target.value) : "";
  const exercises = [...workoutState.exercises];

  exercises[exIndex].sets[setIndex] = { // <-- mutates exercises[exIndex]
    ...exercises[exIndex].sets[setIndex],
    [e.target.name]: value,
  };
  setWorkoutState({
    ...workoutState,
    exercises,
  });
};
输入。我添加了一个
step
属性并附加了curried处理程序。我还将每个输入放在
标签
元素中以便于访问;可以单击标签并聚焦该字段

<div>
  <label>
    reps:{" "}
    <input
      value={set.reps}
      name="reps"
      step={1}
      type="number"
      onChange={handleOnChange(exIndex, setIndex)}
    />
  </label>
</div>
<div>
  <label>
    weight:{" "}
    <input
      value={set.weight}
      name="weight"
      step={0.1}
      type="number"
      onChange={handleOnChange(exIndex, setIndex)}
    />
  </label>
</div>

代表:{'}
重量:{'}

完整代码:

const workout = {
  id: "123-234sdf-1213",
  name: "wo name",
  done: false,
  exercises: [
    {
      name: "back squat",
      sets: [
        {
          number: 0,
          reps: 0,
          weight: 0,
          done: false
        },
        {
          number: 1,
          reps: 0,
          weight: 0,
          done: false
        },
        {
          number: 2,
          reps: 0,
          weight: 0,
          done: false
        }
      ]
    },
    {
      name: "leg press",
      sets: [
        {
          number: 0,
          reps: 0,
          weight: 0,
          done: false
        },
        {
          number: 1,
          reps: 0,
          weight: 0,
          done: false
        },
        {
          number: 2,
          reps: 0,
          weight: 0,
          done: false
        }
      ]
    }
  ]
};

export default function App() {
  const [workoutState, setWorkoutState] = useState(workout);

  const handleOnChange = (eIndex, sIndex) => (e) => {
    const { name, value } = e.target;

    setWorkoutState((workoutState) => ({
      ...workoutState,
      exercises: workoutState.exercises.map((exercise, exerciseIndex) =>
        exerciseIndex === eIndex
          ? {
              ...exercise,
              sets: exercise.sets.map((set, setIndex) =>
                setIndex === sIndex
                  ? {
                      ...set,
                      [name]: Number(value)
                    }
                  : set
              )
            }
          : exercise
      )
    }));
  };

  return (
    <div className="App">
      <h1>{workoutState.name}</h1>
      {workoutState.exercises.map((ex, exIndex) => (
        <>
          <h2>{ex.name}</h2>
          {ex.sets.map((set, setIndex) => (
            <div key={`${ex.name}_${setIndex}`}>
              <h3>Set {setIndex}</h3>
    <div>
      <label>
        reps:{" "}
        <input
          value={set.reps}
          name="reps"
          step={1}
          type="number"
          onChange={handleOnChange(exIndex, setIndex)}
        />
      </label>
    </div>
    <div>
      <label>
        weight:{" "}
        <input
          value={set.weight}
          name="weight"
          step={0.1}
          type="number"
          onChange={handleOnChange(exIndex, setIndex)}
        />
      </label>
    </div>
            </div>
          ))}
        </>
      ))}
    </div>
  );
}
const锻炼={
id:“123-234sdf-1213”,
名称:“工单名称”,
完成:错误,
练习:[
{
名称:“后蹲”,
设置:[
{
编号:0,
代表:0,,
重量:0,,
完成:错误
},
{
编号:1,
代表:0,,
重量:0,,
完成:错误
},
{
编号:2,
代表:0,,
重量:0,,
完成:错误
}
]
},
{
名称:“腿部按压”,
设置:[
{
编号:0,
代表:0,,
重量:0,,
完成:错误
},
{
编号:1,
代表:0,,
重量:0,,
完成:错误
},
{
编号:2,
代表:0,,
重量:0,,
完成:错误
}
]
}
]
};
导出默认函数App(){
const[workoutState,setWorkoutState]=使用状态(训练);
常数变化=(eIndex,sIndex)=>(e)=>{
常量{name,value}=e.target;
setWorkoutState((workoutState)=>({
…美国,
练习:workoutState.exercises.map((练习,练习索引)=>
exerciseIndex==eIndex
? {
运动
集合:exercise.sets.map((集合,集合索引)=>
setIndex==sIndex
? {
设置
[名称]:编号(值)
}
:设置
)
}
:练习
)
}));
};
返回(
{workoutState.name}
{workoutState.exercises.map((ex,exIndex)=>(
{ex.name}
{ex.sets.map((set,setIndex)=>(
集合{setIndex}
代表:{'}
重量:{'}
))}
))}
);
}

但我似乎无法删除de first 0Hi@DavideCariani您能否澄清一下您“无法删除[the]”的意思第一个0?你指的是你的
训练中的默认重复次数/重量值吗?练习
数组?嘿@DrewReese,是的,我的意思是不可能删除第一个0。在沙箱中你可以看到它。@DavideCariani啊,好的,如果你将
[名称]:数字(值)
更改为
[名称]:value
您可以在输入中将空格从“0”返回到空字符串。
const workout = {
  id: "123-234sdf-1213",
  name: "wo name",
  done: false,
  exercises: [
    {
      name: "back squat",
      sets: [
        {
          number: 0,
          reps: 0,
          weight: 0,
          done: false
        },
        {
          number: 1,
          reps: 0,
          weight: 0,
          done: false
        },
        {
          number: 2,
          reps: 0,
          weight: 0,
          done: false
        }
      ]
    },
    {
      name: "leg press",
      sets: [
        {
          number: 0,
          reps: 0,
          weight: 0,
          done: false
        },
        {
          number: 1,
          reps: 0,
          weight: 0,
          done: false
        },
        {
          number: 2,
          reps: 0,
          weight: 0,
          done: false
        }
      ]
    }
  ]
};

export default function App() {
  const [workoutState, setWorkoutState] = useState(workout);

  const handleOnChange = (eIndex, sIndex) => (e) => {
    const { name, value } = e.target;

    setWorkoutState((workoutState) => ({
      ...workoutState,
      exercises: workoutState.exercises.map((exercise, exerciseIndex) =>
        exerciseIndex === eIndex
          ? {
              ...exercise,
              sets: exercise.sets.map((set, setIndex) =>
                setIndex === sIndex
                  ? {
                      ...set,
                      [name]: Number(value)
                    }
                  : set
              )
            }
          : exercise
      )
    }));
  };

  return (
    <div className="App">
      <h1>{workoutState.name}</h1>
      {workoutState.exercises.map((ex, exIndex) => (
        <>
          <h2>{ex.name}</h2>
          {ex.sets.map((set, setIndex) => (
            <div key={`${ex.name}_${setIndex}`}>
              <h3>Set {setIndex}</h3>
    <div>
      <label>
        reps:{" "}
        <input
          value={set.reps}
          name="reps"
          step={1}
          type="number"
          onChange={handleOnChange(exIndex, setIndex)}
        />
      </label>
    </div>
    <div>
      <label>
        weight:{" "}
        <input
          value={set.weight}
          name="weight"
          step={0.1}
          type="number"
          onChange={handleOnChange(exIndex, setIndex)}
        />
      </label>
    </div>
            </div>
          ))}
        </>
      ))}
    </div>
  );
}