为何子组件触发的setState内console.log能获取更新后状态?
React状态更新后console.log输出差异的原因
CASE 1:状态更新后输出旧值
在titleChangeHandler中调用setCurrentTitle后,立即console.log(currentTitle)会输出旧的状态值。
import "./ExpenseForm.css"; import { useState } from "react"; const ExpenseForm = (props) => { const [currentTitle, setCurrentTitle] = useState(""); const [currentAmount, setCurrentAmount] = useState(""); const [currentDate, setCurrentDate] = useState(""); const titleChangeHandler = (event) => { setCurrentTitle(event.target.value); console.log(currentTitle); // 输出旧值 }; const amountChangeHandler = (event) => { setCurrentAmount(event.target.value); }; const dateChangeHandler = (event) => { setCurrentDate(event.target.value); }; const submitHandler = (event) => { event.preventDefault(); const expenseData = { title: currentTitle, amount: currentAmount, date: currentDate, }; props.onSaveExpenseData(expenseData); setCurrentAmount(""); setCurrentTitle(""); setCurrentDate(""); }; return ( <form onSubmit={submitHandler}> <div className="new-expense__controls"> <div className="new-expense__control"> <label>Title</label> <input type="text" value={currentTitle} onChange={titleChangeHandler} /> </div> <div className="new-expense__control"> <label>Amount</label> <input type="number" min="0.1" step="0.1" value={currentAmount} onChange={amountChangeHandler} /> </div> <div className="new-expense__control"> <label>Date</label> <input type="date" min="2019-01-01" max="2022-12-31" value={currentDate} onChange={dateChangeHandler} /> </div> </div> <div className="new-expense__actions"> <button type="submit">Add expense</button> </div> </form> ); }; export default ExpenseForm;
CASE 2:状态更新后输出新值
将onSelectYear函数通过props传给子组件ExpensesFilter,在子组件中调用该函数时,内部setYear后console.log(year)会输出最新值。
Expenses.js
import "./Expenses.css"; import ExpenseItem from "./ExpenseItem"; import React, { useState } from "react"; import ExpensesFilter from "./ExpenseFilter"; import Card from "../UI/Card"; const Expenses = (props) => { const [year, setYear] = useState("2020"); const onSelectYear = (year) => { setYear(year); console.log(year); // 输出新值 }; return ( <div> <Card className="expenses"> <ExpensesFilter selectedYear={year} onSelectYear={onSelectYear} ></ExpensesFilter> {props.expenses.map(expense => ( <ExpenseItem key={expense.id} title={expense.title} amount={expense.amount} date={expense.date} /> ))} </Card> </div> ); }; export default Expenses;
ExpenseFilter.js
import React from "react"; import "./ExpenseFilter.css"; const ExpensesFilter = (props) => { const onSelectChange = (event) => { props.onSelectYear(event.target.value); }; return ( <div className="expenses-filter"> <div className="expenses-filter__control"> <label>Filter by year</label> <select value={props.selectedYear} onChange={onSelectChange}> <option value="2022">2022</option> <option value="2021">2021</option> <option value="2020">2020</option> <option value="2019">2019</option> </select> </div> </div> ); }; export default ExpensesFilter;
差异原因
核心区别在于你打印的不是同一个对象:
CASE 1:你打印的是组件的状态变量
currentTitle。React的状态更新是异步且批量调度的,当前事件处理函数执行期间,状态变量还未更新——因为函数闭包捕获的是更新前的状态值,所以打印出旧值。CASE 2:你打印的是
onSelectYear函数的参数year,这个参数是子组件传过来的event.target.value(即最新选中的年份),和React的状态更新异步性完全无关。你只是把这个参数传给setYear,然后直接打印参数本身,自然是最新值。
如果把CASE 2的代码改成打印组件的状态变量year,结果就会和CASE 1一致:
const onSelectYear = (newYear) => { setYear(newYear); console.log(year); // 这里打印状态变量,会输出旧值 };
内容的提问来源于stack exchange,提问作者Jatin Damariya
相关产品推荐
相关产品推荐

