React 状态更新的异步特性
·
1. React 状态更新机制
React 中的状态更新( setState )是 异步 的,这意味着:
// 修复前的问题代码
onChange={val => {
const newSearchForm = { ...searchForm, teacher_name: val || undefined };
setSearchForm(newSearchForm); // ← 这里是异步更新
setPage(1);
fetchData(1, true); // ← 这里调用时,searchForm 还是旧值!
}}
当 setSearchForm(newSearchForm) 被调用时, searchForm 状态并不会立即更新,而是在下一次渲染时才会更新。但紧接着调用的 fetchData(1, true) 仍然会使用旧的 searchForm 值。
2. useCallback 的闭包陷阱
fetchData 函数使用了 useCallback :
const fetchData = useCallback(async (pageNum: number = 1, reset: boolean = false) => {
// 这里的 searchForm 是闭包中捕获的值
const params = {
page: pageNum,
pageSize: 10,
year: searchForm.year || null, // 使用的是闭包中的旧值
teacherArray: searchForm.teacher_name ? [searchForm.teacher_name] : null
};
// ...
}, [searchForm]); // 依赖项只有 searchForm
闭包问题 : useCallback 创建的函数会"记住"创建时的 searchForm 值,即使在 onChange 中调用 setSearchForm 更新了状态, fetchData 函数内部仍然使用的是旧的 searchForm 值。
修复前:
// 问题代码
onChange={val => {
const newSearchForm = { ...searchForm, teacher_name: val || undefined };
setSearchForm(newSearchForm); // 异步更新
setPage(1);
fetchData(1, true); // 使用旧的 searchForm
}}
// fetchData 函数
const fetchData = useCallback(async (pageNum: number = 1, reset: boolean = false) => {
const params = {
year: searchForm.year || null, // 旧值
teacherArray: searchForm.teacher_name ? [searchForm.teacher_name] : null // 旧值
};
// ...
}, [searchForm]);
修复后:
// 修复后的代码
onChange={val => {
const newSearchForm = { ...searchForm, teacher_name: val || undefined };
setSearchForm(newSearchForm);
setPage(1);
fetchData(1, true, newSearchForm); // 直接传递新值
}}
// 修改后的 fetchData 函数
const fetchData = useCallback(async (pageNum: number = 1, reset: boolean = false, customSearchForm?: SearchFormType) => {
// 使用传入的 customSearchForm 或当前的 searchForm
const currentSearchForm = customSearchForm || searchForm;
const params = {
year: currentSearchForm.year || null, // 使用最新值
teacherArray: currentSearchForm.teacher_name ? [currentSearchForm.teacher_name] : null // 使用最新值
};
// ...
}, [searchForm]);
我的解决方案是在 fetchData 函数中添加一个可选的 customSearchForm 参数,允许直接传入最新的搜索表单数据,而不依赖于可能还未更新的状态。
修改 fetchData 函数签名 :
const fetchData = useCallback(async (
pageNum: number = 1,
reset: boolean = false,
customSearchForm?: SearchFormType // 新增可选参数
) => {
使用最新的搜索表单数据 :
// 优先使用传入的 customSearchForm,否则使用当前状态
const currentSearchForm = customSearchForm || searchForm;
在 onChange 中传递新数据 :
onChange={val => {
const newSearchForm = { ...searchForm, teacher_name: val || undefined };
setSearchForm(newSearchForm);
setPage(1);
fetchData(1, true, newSearchForm); // 直接传递新创建的表单数据
}}
不再依赖状态更新后的值,而是直接使用刚创建的 newSearchForm
更多推荐



所有评论(0)