You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

React遍历列表时实现单个输入框独立状态绑定的技术问题咨询

解决React列表中输入框同步更新的问题

嘿,我一眼就看出问题所在了——你所有的编辑输入框都绑定了同一个全局状态变量(day、from、until),不管你编辑哪一项,修改的都是这几个全局值,自然所有输入框都会同步显示相同内容。咱们来调整一下,让每个输入框只和对应的训练项绑定:

核心思路

不再用全局的day/from/until来存储编辑中的值,而是为当前正在编辑的训练项单独维护临时状态,这样每个输入框只会响应对应项的编辑操作。

修改后的完整代码

import React, { useState, useEffect } from 'react'
import axios from 'axios'

function Training({ teamid }) {
 const [isTrainingExisting, setIsTrainingExisting] = useState(false);
 const [trainingData, setTrainingData] = useState([]);
 const [addTraining, setAddTraining] = useState(false);
 // 拆分新增和编辑的状态:新增训练用独立的全局状态
 const [newDay, setNewDay] = useState('');
 const [newFrom, setNewFrom] = useState('');
 const [newUntil, setNewUntil] = useState('');

 const getTrainingData = () => {
 axios
 .get(`${process.env.REACT_APP_API_URL}/team/team_training-${teamid}`)
 .then((res) => {
 if (res.status === 200) {
 if (res.data?.length > 0) {
 setIsTrainingExisting(true)
 setTrainingData(res.data)
 } else {
 setIsTrainingExisting(false)
 }
 }
 })
 .catch((error) => {
 console.log(error);
 });
 }

 useEffect(() => {
 getTrainingData();
 }, []);

 const deleteTraining = (id) => {
 axios
 .delete(`${process.env.REACT_APP_API_URL}/team/delete/team_training-${teamid}`, {
 data: { trainingsid: `${id}` }
 })
 .then((res) => {
 if (res.status === 200) {
 const updatedTrainings = trainingData.filter(obj => obj.trainingsid !== id);
 setTrainingData([...updatedTrainings]);
 }
 })
 .catch((error) => {
 console.log(error);
 });
 }

 const addNewTraining = () => {
 setAddTraining(true);
 }

 const addTrainingNew = () => {
 axios
 .post(`${process.env.REACT_APP_API_URL}/team/add/team_training-${teamid}`, {
 von: newFrom, 
 bis: newUntil, 
 tag: newDay
 })
 .then((res) => {
 if (res.status === 200) {
 setAddTraining(false)
 const newTraining = {
 trainingsid: res.data,
 mannschaftsid: teamid,
 von: newFrom,
 bis: newUntil,
 tag: newDay
 }
 setTrainingData([...trainingData, newTraining]);
 // 清空新增表单
 setNewDay('');
 setNewFrom('');
 setNewUntil('');
 }
 })
 .catch((error) => {
 console.log(error);
 });
 }

 // 用对象存储当前编辑的项ID和临时值,初始为null
 const [editingItem, setEditingItem] = useState(null);

 const editingTraining = (training) => {
 // 点击编辑时,把当前项的原始数据存入临时状态
 setEditingItem({
 id: training.trainingsid,
 tag: training.tag,
 von: training.von,
 bis: training.bis
 });
 };

 const updateTraining = () => {
 if (!editingItem) return;
 // 调用API更新训练数据
 axios
 .put(`${process.env.REACT_APP_API_URL}/team/update/team_training-${teamid}`, {
 trainingsid: editingItem.id,
 von: editingItem.von,
 bis: editingItem.bis,
 tag: editingItem.tag
 })
 .then((res) => {
 if (res.status === 200) {
 // 更新本地trainingData,替换已编辑的项
 const updatedTrainings = trainingData.map(item => 
 item.trainingsid === editingItem.id 
 ? {...item, ...editingItem} 
 : item
 );
 setTrainingData(updatedTrainings);
 // 退出编辑状态
 setEditingItem(null);
 }
 })
 .catch((error) => {
 console.log(error);
 });
 }

 return (
 <div>
 {trainingData.map((d) => (
 <div key={d.trainingsid}>
 Trainingszeiten
 {/* 输入框绑定逻辑:仅当前编辑项显示临时值,否则显示原始数据 */}
 <input 
 className="input is-normal" 
 type="text" 
 value={editingItem?.id === d.trainingsid ? editingItem.tag : d.tag} 
 placeholder="Wochentag" 
 onChange={(event) => {
 if (editingItem?.id === d.trainingsid) {
 // 更新临时编辑状态时保留其他字段
 setEditingItem({...editingItem, tag: event.target.value});
 }
 }} 
 disabled={editingItem?.id !== d.trainingsid}
 />
 <input 
 className="input is-normal" 
 type="text" 
 value={editingItem?.id === d.trainingsid ? editingItem.von : d.von} 
 placeholder="Von" 
 onChange={(event) => {
 if (editingItem?.id === d.trainingsid) {
 setEditingItem({...editingItem, von: event.target.value});
 }
 }} 
 disabled={editingItem?.id !== d.trainingsid}
 />
 <input 
 className="input is-normal" 
 type="text" 
 value={editingItem?.id === d.trainingsid ? editingItem.bis : d.bis} 
 placeholder="Bis" 
 onChange={(event) => {
 if (editingItem?.id === d.trainingsid) {
 setEditingItem({...editingItem, bis: event.target.value});
 }
 }} 
 disabled={editingItem?.id !== d.trainingsid}
 />
 {/* 非编辑状态下显示原始数据 */}
 {editingItem?.id !== d.trainingsid && (
 <span>{d.tag} - {d.von} bis {d.bis} Uhr</span>
 )}
 <button className="button is-danger" onClick={() => deleteTraining(d.trainingsid)}>Löschen</button>
 {editingItem?.id === d.trainingsid ? (
 <button className="button is-success" onClick={updateTraining}>Save</button>
 ) : (
 <button className="button is-info" onClick={() => editingTraining(d)}>Edit</button>
 )}
 <br />
 </div>
 ))}

 {/* 渲染新增训练的表单(你之前的代码遗漏了这部分) */}
 {addTraining && (
 <div>
 <input 
 className="input is-normal" 
 type="text" 
 value={newDay} 
 placeholder="Wochentag" 
 onChange={(e) => setNewDay(e.target.value)} 
 />
 <input 
 className="input is-normal" 
 type="text" 
 value={newFrom} 
 placeholder="Von" 
 onChange={(e) => setNewFrom(e.target.value)} 
 />
 <input 
 className="input is-normal" 
 type="text" 
 value={newUntil} 
 placeholder="Bis" 
 onChange={(e) => setNewUntil(e.target.value)} 
 />
 <button className="button is-success" onClick={addTrainingNew}>Hinzufügen</button>
 <button className="button is-light" onClick={() => setAddTraining(false)}>Abbrechen</button>
 </div>
 )}

 <button className="button is-primary" onClick={addNewTraining}>Neues Training hinzufügen</button>
 </div>
 )
 }

 export default Training

关键改动说明

  1. 拆分状态:把新增训练和编辑训练的状态完全分开,新增用独立的全局状态,编辑用editingItem对象存储当前项的临时值,避免状态冲突。
  2. 输入框独立绑定:每个输入框仅在对应项处于编辑状态时,绑定editingItem里的临时值,非编辑状态显示原始数据,且只有编辑中的输入框可操作。
  3. 优化列表key:把列表的key从索引i改成唯一标识d.trainingsid,避免列表更新时出现不必要的渲染错误。
  4. 完善编辑流程:点击编辑时初始化临时值,保存时同步更新API和本地数据,确保状态一致性。

这样修改后,每个输入框就只会和对应的训练项绑定,编辑操作再也不会影响其他输入框啦!

内容的提问来源于stack exchange,提问作者Mr. Hankey

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.30 07:24:05