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

ReactJS状态更新后输入框值未同步问题求助

问题:作物种植面积输入框值无法同步状态更新

我正在实现一个作物列表功能,用户可修改每种作物的种植面积(surface)、产量(yield)和价格(price)。初始状态下所有作物的面积为0,产量和价格已预设,初始状态如下:

C1 : ['Blé tendre', 0, 8.3, 191]
C2 : ["Orge d'hivers et escourgeon", 0, 6.75, 181]
C3 : ['Maïs grain', 0, 9.99, 178]
C4 : ['Soja', 0, 2.73, 379]

当用户在"Blé tendre"的面积输入框中输入20时,console.log显示状态已更新:

C1 : ['Blé tendre', 20, 8.3, 191]
C2 : ["Orge d'hivers et escourgeon", 0, 6.75, 181]
C3 : ['Maïs grain', 0, 9.99, 178]
C4 : ['Soja', 0, 2.73, 379]

但输入框的值并未同步变化。

主文件 Assolement.js

import React, { useState} from 'react';
import {Navigate} from 'react-router-dom'
import Entete from '../MEP/entete'
import Culture from './culture_assol'

function Assolement() {
  const [goToExploit, setGoToExploit] = useState(false)
  const [data, setData] = useState({"C1": ["Blé tendre", 0,8.3, 191], "C2": ["Orge d'hivers et escourgeon",0, 6.75, 181], "C3" :["Maïs grain",0, 9.99, 178], "C4": ["Soja",0, 2.73, 379]})

  const table_assol=  Object.keys(data).map(key => (
    <Culture 
    keys={key}
    data={data}
    MAJ_surf={MAJ_surf}
    libelle={data[key][0]}
    />
  ))

  function MAJ_surf(key,surf) {
    var newData= data;
    newData[key][1] = parseFloat(surf)//execute the manipulations
    setData(newData)
    setData(prev => {
      return prev;
    })
    console.log('surf')
    console.log(surf)
    console.log('data')
    console.log(data)
    console.log(data[key][1])    
  }

  function handleSubmit(event) {
    event.preventDefault()
    setGoToExploit(true)
  }

  if(goToExploit) {
    return <Navigate push to={`/exploitation`}/>
  }

  return (
    <div>
      <Entete titre="Assolement"/>
      <div className='container'>
        <h1>  </h1>
        <form onSubmit={handleSubmit}>
          <div className='table_assol'>
            {table_assol}
          </div>
          <div className='row'>
            <button type='submit' className='validation'> Enregistrer </button>
          </div>
        </form>
      </div>
    </div>
  );
}

export default Assolement;

子组件 culture_assol.js

import React from 'react'

const Culture = ({keys,data, MAJ_surf, libelle}) => {
    function handleChangeSurface(event) {
        var surf = event.target.value;
        MAJ_surf(keys, surf);
        console.log(data)
        console.log(data[keys])
        console.log(data[keys][1])
    }

    return (
        <div className='row ligne_assol'>
            <div className='col_assol col_libelle'>
            {libelle}
            </div>
            <div className='col_assol col_surface'>
            <div className='videBlocAssol'>
                <input 
                className='input_assol'
                onChange={handleChangeSurface}
                value= {data[keys][1]}
                placeholder='0'
                type='text'/>
                <div className='pleinBlocAssol'>
                ha
                </div>
            </div>
            </div>
            <div className='col_assol col_rdt'>
            <div className='videBlocAssol'>
            <input 
                className='input_assol'
                value= {data[keys][2]}
                type='text'/>
                <div className='pleinBlocAssol'>
                t/ha
                </div>
            </div>
            </div>
            <div className='col_assol col_prix'>
            <div className='videBlocAssol'>
                <input 
                className='input_assol'
                value= {data[keys][3]}
                type='text'/>
                <div className='pleinBlocAssol'>
                €/t
                </div>
            </div>
            </div>
            <div className='col_assol col_PB_unitaire'>
            {Math.round(data[keys][2]*data[keys][3])} €
            </div>
            <div className='col_assol col_PB_tit_Prod'>
            {Math.round(data[keys][1]*data[keys][2]*data[keys][3])} €
            </div>
        </div>
    )
}
export default Culture;

已尝试的方法

  • 将MAJ_surf函数移至culture_assol组件内
  • 移除重复的setData调用,仅保留setData(newData)

解决方案

问题核心是直接修改原状态对象,未创建新引用,React依赖状态引用变化触发重新渲染。

1. 修复状态更新逻辑

修改MAJ_surf函数,创建状态的深拷贝后再修改,确保生成新的引用:

function MAJ_surf(key, surf) {
  setData(prevData => {
    // 拷贝外层对象
    const newData = {...prevData};
    // 拷贝对应作物的数组,修改面积值
    newData[key] = [...prevData[key]];
    newData[key][1] = parseFloat(surf);
    return newData;
  });
}

这种方式比JSON.parse(JSON.stringify(data))更高效,且能兼容JSON无法序列化的类型。

2. 优化组件key传递

React列表渲染需要指定key属性,修正table_assol的map逻辑:

const table_assol=  Object.keys(data).map(key => (
  <Culture 
    key={key} // React要求的列表项key属性
    keys={key} // 自定义参数,用于访问data
    data={data}
    MAJ_surf={MAJ_surf}
    libelle={data[key][0]}
  />
))

失效原因说明

之前的代码中var newData = data只是复制了原状态的引用,修改newData[key][1]本质是直接修改原状态对象。React对比前后状态时发现引用未变,不会触发组件重新渲染,因此输入框值无法更新。即使调用setData(prev => prev),由于引用未变,依然不会触发渲染。

内容的提问来源于stack exchange,提问作者Aliénor

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.17 12:30:56