场景: 上传一个excel 解析excel表格,填入数据bomTableData。 使用数据渲染表格 同时 使用此数据进行http请求,获取response结果,再次赋值bomTableData,重新渲染。
React
数据为空
1interface Props {
2 setBomOriginData: (data: BomTableData[]) => void,
3 bomOriginData: BomTableData[],
4}
5
6 const handleFileChange = (event) => {
7 const file = event.target.files[0];
8 if (file) {
9 readFile(file)
10 .then(async (fileData) => {
11 const parsedData = await parseExcel(fileData);
12 const data = parsedData.slice(1);
13 setBomOriginData(
14 data.map((item: string[]) => {
15 return { original_demand: item.join(" ") };
16 })
17 );
18 setTimeout(() => {
19 console.log(data, bomOriginData); // data 有数据 bomOriginData 为 []
20 parserBom(); // 用excel数据 请求接口
21 }, 0);
22 })
23 .catch((error) => {
24 console.error("Error reading or parsing file:", error);
25 });
26 }
27 };
经查询得知:setState
是异步的,这意味着当你调用 setBomOriginData
时,状态更新并不会立即反映在下一行代码中。在 setTimeout
中打印 bomOriginData
时,bomOriginData
可能仍然是旧值。
为了在状态更新后立即执行某些操作,你可以使用 useEffect
来监控状态的变化。当 bomOriginData
更新时,useEffect
将被触发,并在新的状态值可用时执行你需要的操作。
使用useEffect(没有完美解决)
1useEffect(() => {
2 if (bomOriginData.length > 0) {
3 console.log("bomOriginData-------", bomOriginData);
4 parserBom();
5 }
6 }, [bomOriginData]);
7
8
9const handleFileChange = (event) => {
10 const file = event.target.files[0];
11 if (file) {
12 readFile(file)
13 .then(async (fileData) => {
14 const parsedData = await parseExcel(fileData);
15 const data = parsedData.slice(1);
16 setBomOriginData(
17 data.map((item: string[]) => {
18 return { original_demand: item.join(" ") };
19 })
20 );
21 })
22 .catch((error) => {
23 console.error("Error reading or parsing file:", error);
24 });
25 }
26 };
27
28 const parserBom = async () => {
29 const url = "**********";
30 controller.current = new AbortController();
31 const { signal } = controller.current;
32 const reqData = {
33 method: "POST",
34 headers: {
35 "Content-Type": "application/json",
36 },
37 body: JSON.stringify({
38 bomData: bomOriginData,
39 }),
40 signal: signal,
41 };
42
43 try {
44 const result = await fetch(url, reqData);
45 const json: fetchResult = await result.json();
46 const { code, response, responseError } = json;
47 if (code === 200) {
48 setBomOriginData(response?.map((item) => item));
49 messageAlert("success", "解析成功");
50 } else if (code === 500) {
51 handleClear();
52 messageAlert("error", responseError?.message);
53 }
54 } catch (error: any) {
55 ******
56 } finally {
57 ******
58 }
59 };
60
确实 在useEffect
中打印 bomOriginData
是正常值。 但是在 parserBom()
中 再次调用setBomOriginData()
useEffect
再次触发,出现死循环。
添加变量标记,优化useEffect (问题解决)
1const [shouldParseBom, setShouldParseBom] = useState(false);
2
3useEffect(() => {
4 if (shouldParseBom) {
5 console.log("Updated bomOriginData:", bomOriginData);
6 parserBom();
7 setShouldParseBom(false); // 重置 shouldParseBom 以避免死循环
8 }
9 }, [bomOriginData, shouldParseBom]);
10
11 const handleFileChange = (event) => {
12 const file = event.target.files[0];
13 if (file) {
14 readFile(file)
15 .then(async (fileData) => {
16 const parsedData = await parseExcel(fileData);
17 const data = parsedData.slice(1);
18 setBomOriginData(
19 data.map((item: string[]) => {
20 return { original_demand: item.join(" ") };
21 })
22 );
23 setShouldParseBom(true);
24 })
25 .catch((error) => {
26 console.error("Error reading or parsing file:", error);
27 });
28 }
29 };
Vue
1const bomOriginData = defineModel("bomParseTableData", {
2 type: Array as () => BomParserResponse[],
3 default: () => [],
4});
5
6const handleFileChange = async (event: any) => {
7 const file = event.target.files[0];
8
9 if (file) {
10 readFile(file)
11 .then(async (fileData) => {
12 bomData.value = await parseExcel(fileData);
13 const data = bomData.value.slice(1);
14 nextTick(() => {
15 bomOriginData.value = data.map((item: string[]) => {
16 return { original_demand: item.join(" ") };
17 })
18 parserBom();
19 });
20 })
21 .catch((error) => {
22 console.error("Error reading or parsing file:", error);
23 });
24 }
25};
对比 React Vue
在React中 由于 setState
是异步的 需要使用 useEffect 结合 setBomOriginData
做状态更新 并且还要定义shouldParseBom
来做更新标记。
在Vue中,得益于 defineModel
、 nextTick
API ,可直接修改。
个人笔记记录 2021 ~ 2025