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

React输入表单无法记录最后一个字符的问题求助

问题描述

我希望将输入内容记录到一个对象中用于图表展示,目前功能大体正常,但输入第一个字符时仅生成空对象,导致最后输入的一个字符无法被记录到对象中,该如何解决?

项目代码托管在GitHub仓库 expense_chart_component

主组件代码

import SpendingGraph from "./SpendingGraph";
import ThisMonth from "./ThisMonth";
import WeekInput from "./WeekInput";
import { useState } from "react";
import { useSelector, useDispatch } from "react-redux";
import { appear } from "/Users/Fauxir/Desktop/CSS-HTML-JS-REACT practice/expense_chart_component/src/redux/showSlice";

function MainComp() {
  const [values, setValues] = useState({});
  const see = useSelector((state) => state.show.value);
  const dispatch = useDispatch();
  const onChange = (e) => {
    setValues({ ...values, [e.target.placeholder]: e.target.value });
    //setDaySpending({...daySpending, [e.target.id]: e.target.value })
    console.log(values);
    //console.log(daySpending)
  };

  const inputs = [
    { placeholder: "Spent Monday", id: 1 },
    { placeholder: "Spent Tuesday", id: 2 },
    { placeholder: "Spent Wednesday", id: 3 },
    { placeholder: "Spent Thursday", id: 4 },
    { placeholder: "Spent Friday", id: 5 },
    { placeholder: "Spent Saturday", id: 6 },
    { placeholder: "Spent Sunday", id: 7 },
  ];

  return (
    <div className="bg-bridal-heath-500 w-80 h-fit rounded-lg flex flex-col items-center justify-between">
      {!see
        ? inputs.map((input) => (
            <WeekInput key={input.id} {...input} onInput={onChange} />
          ))
        : null}
      {see ? <SpendingGraph /> : null}
      {see ? <ThisMonth /> : null}
      <input onBlur={onChange}></input>
      {!see ? (
        <div
          onClick={() => dispatch(appear())}
          className="h-12 w-72 bg-terracotta-600  flex flex-row items-center justify-center rounded-md cursor-pointer mt-6 hover:bg-terracotta-500 hover:shadow-sambuca-300 hover:shadow-lg mb-8"
        >
          <div>Calculate</div>
        </div>
      ) : null}
    </div>
  );
}

export default MainComp;

输入组件代码

function WeekInput(props) {
  const { placeholder, onChange, ...inputProps } = props;

  return (
    <div className="h-8 w-2/4 flex flex-col  justify-center mt-4">
      <input
        className="bg-bridal-heath-500 leading-none rounded-sm shadow-sm focus:outline-none focus:shadow-outline text-gray-600 font-medium border-sambuca-300 border-2"
        placeholder={placeholder}
        {...inputProps}
        onChange={onChange}
      ></input>
    </div>
  );
}

export default WeekInput;
解决方案

这个问题的核心是React useState的更新是异步的,你在调用setValues后立即console.log(values),打印的是更新前的旧值,所以会误以为第一个字符没被记录;另外,依赖当前values状态更新时,普通方式可能会因为异步导致状态滞后,需要改用函数式更新。

修改步骤:

  1. 把setValues改成函数式更新,确保每次都基于最新状态:
const onChange = (e) => {
  // prevValues是React传入的当前最新状态
  setValues(prevValues => ({ 
    ...prevValues, 
    [e.target.placeholder]: e.target.value 
  }));
};
  1. 如果要确认状态是否正确更新,不要在setValues后直接打印,添加useEffect监听状态变化:
// 导入useEffect
import { useState, useEffect } from "react";

// 在MainComp组件内部添加
useEffect(() => {
  console.log("当前values状态:", values);
}, [values]); // 仅当values变化时执行
  1. 移除主组件中多余的<input onBlur={onChange}></input>,这个输入框没有placeholder,会导致对象中出现空键值对,干扰数据记录。

原理说明:

  • 函数式更新会获取到最新的状态快照,避免了异步更新带来的状态不一致问题,确保每次输入的字符都能正确被记录到对象中。
  • 直接在setValues后打印values,由于状态更新是异步的,此时values还是旧值,所以会出现“空对象”的错觉,实际上状态已经正确更新了。

内容的提问来源于stack exchange,提问作者Mihai Tohaneanu

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.16 18:40:32