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状态更新时,普通方式可能会因为异步导致状态滞后,需要改用函数式更新。
修改步骤:
- 把
setValues改成函数式更新,确保每次都基于最新状态:
const onChange = (e) => { // prevValues是React传入的当前最新状态 setValues(prevValues => ({ ...prevValues, [e.target.placeholder]: e.target.value })); };
- 如果要确认状态是否正确更新,不要在
setValues后直接打印,添加useEffect监听状态变化:
// 导入useEffect import { useState, useEffect } from "react"; // 在MainComp组件内部添加 useEffect(() => { console.log("当前values状态:", values); }, [values]); // 仅当values变化时执行
- 移除主组件中多余的
<input onBlur={onChange}></input>,这个输入框没有placeholder,会导致对象中出现空键值对,干扰数据记录。
原理说明:
- 函数式更新会获取到最新的状态快照,避免了异步更新带来的状态不一致问题,确保每次输入的字符都能正确被记录到对象中。
- 直接在
setValues后打印values,由于状态更新是异步的,此时values还是旧值,所以会出现“空对象”的错觉,实际上状态已经正确更新了。
内容的提问来源于stack exchange,提问作者Mihai Tohaneanu
相关产品推荐
相关产品推荐

