三步学会 React(Vue 开发者视角)
如果你已经有 Vue 的开发经验,并且初步了解过 React,那么这篇文章将帮你快速上手 React 的核心使用方式。
第一关:理解数据的异步更新
在 Vue 中,数据更新是同步的:你修改了数据,紧接着使用它,拿到的一定是最新值。
而在 React 中,状态更新是异步的,如果你在 setState 后立即读取状态,拿到的还是旧值。
我们通过一个“年级成绩查询”的多级筛选表单来理解这个问题。
需求描述
-
一级筛选:选择年级(一年级 ~ 六年级)
-
二级筛选:选择学科(不同年级对应不同学科)
-
每次筛选变动,都要实时查询对应学生列表
Vue 实现(正常)
<template></template>
<script setup>
const searchParams = reactive({
grade: undefined,
subject: undefined,
});
const searchOptions = reactive({
grade: [],
subject: [],
});
const studentList = ref([]);
const init = () => {
getGradeListApi().then(res => {
searchOptions.grade = res;
gradeChange(res[0].value);
});
};
init();
const gradeChange = value => {
searchParams.grade = value;
getSubjectListApi({ grade: searchParams.grade }).then(res => {
searchOptions.subject = res;
subjectChange(res[0].value);
});
};
const subjectChange = value => {
searchParams.subject = value;
getStudentListApi({
grade: searchParams.grade,
subject: searchParams.subject,
}).then(res => {
studentList.value = res;
});
};
</script>
React 实现(❌ 有问题的版本)
import { useEffect, useState } from "react";
function App() {
const [searchParams, setSearchParams] = useState({
grade: undefined,
subject: undefined,
});
const [searchOptions, setSearchOptions] = useState({
grade: [],
subject: [],
});
const [studentList, setStudentList] = useState([]);
useEffect(() => {
getGradeListApi().then(res => {
setSearchOptions(prev => ({ ...prev, grade: res }));
gradeChange(res[0].value);
});
}, []);
const gradeChange = v => {
setSearchParams(prev => ({ ...prev, grade: v }));
getSubjectListApi({ grade: searchParams.grade }).then(res => {
setSearchOptions(prev => ({ ...prev, subject: res }));
subjectChange(res[0].value);
});
};
const subjectChange = v => {
setSearchParams(prev => ({ ...prev, subject: v }));
getStudentListApi({
grade: searchParams.grade,
subject: searchParams.subject,
}).then(res => {
setStudentList(res);
});
};
return <></>;
}
export default App;
问题出在哪?
在 gradeChange 中,我们调用了 setSearchParams 更新年级,但紧接着在请求学科列表时,searchParams.grade 仍然是旧值。
这就是 React 状态更新的异步性导致的典型问题。
解决方案
有两种常见的解决思路:
方法一:传递最新状态(不推荐)
在每次状态更新时,手动将最新值传给后续函数:
const gradeChange = v => {
const newParams = { ...searchParams, grade: v };
setSearchParams(newParams);
getSubjectListApi({ grade: v }).then(res => {
setSearchOptions(prev => ({ ...prev, subject: res }));
subjectChange(res[0].value, newParams);
});
};
这种方式虽然可行,但容易遗漏传递参数,导致状态不一致。
方法二:使用 useEffect 监听状态变化(✅ 推荐)
将依赖状态的操作放到 useEffect 中,确保使用的是最新状态:
useEffect(() => {
if (searchParams.grade && searchParams.subject) {
getStudentListApi({
grade: searchParams.grade,
subject: searchParams.subject,
}).then(setStudentList);
}
}, [searchParams.grade, searchParams.subject]);
这样,每当 searchParams.grade 或 searchParams.subject 更新时,都会自动触发最新的查询。
小结
- React 中状态更新是异步的,不要在
setState后立即依赖该状态。 - 推荐使用
useEffect,确保使用的是最新状态。 - 对于 Vue 转 React 的开发者来说,这是第一个需要跨越的“实战坑”。
希望这篇文章能帮你顺利迈出 React 实战的第一步!