前阵子面试被问到Github好久没更新了,有些惭愧,因为上面都是我自己日常工作生活使用的,确实也没啥需求。
不过最近觉得足球应用可以做一些优化,正好开了144块Cursor会员,也在B站看了些使用教程,就在昨天开动了。
我的需求是这样的,拉取最近完成的比赛信息,展示、日期、场次,然后胜、平、负、让球胜平负、半全场、比分、总进球的赔率

但是A接口只能返回部分信息,让球胜平负、半全程、比分、总进球的赔率要调用B接口才能拿到
除了模态框架子的搭建我是用了之前写好的"代码片段"生成的,后面的都是跟Cursor说,让他搞,感受到了辅助开发的乐趣,一定程度上实现了异步。
有一次在修改后端node.js脚本时,因为请求接口被腾讯云拦截,我让他处理。他加了些代码,后面我让他去掉,结果他只去掉了前面的代码,没管后面的括号这些,导致文件格式有问题,我让他解决,他竟然删除了这个文件,又自以为是的进行了优化,格式是没问题了,好多功能直接无法使用。
旧代码和新写好的代码混在一起,还好Cursor能回退
然后就是翻页问题,因为翻页涉及到调用详情接口,拿到数据后在更新已有的列表数据。
我就反馈切换页面又问题,让他解决,好几次都不行,甚至有一次他自己加了调试代码,让我把控制台输出发给他,也不行,后面都扯到给表格加key强制更新上去了。
而且越来越差,最后变成加载数据后直接空白....
我一看越来越离谱,还是我自己来吧,发现核心问题在还是和React的响应式设计有关
我大概模拟一下,一开始数据结构是这样的
ini
const loadData = async () => {
const response = await SFootball.getRecentMatches({ startDate, endDate });
if (response.success) {
setLoading(false);
setState({
list: response.data.list,
}));
// 获取第一页的详细赔率信息
await loadCurrentPageOdds(1, 10);
} else {
setLoading(false);
}
};
const loadCurrentPageOdds = async (currentPage: number, pageSize: number) => {
// 获取当前页所有比赛的matchId
const matchIds = state.list
.slice(startIndex, endIndex)
.map((match) => match.matchId);
try {
const oddsResponse = await SFootball.getMatchOddsDetail(matchIds);
if (oddsResponse.success) {
// 检查是否为mock数据
if (oddsResponse.data.isMock) {
message.warning("详情接口请求被拦截,现在使用的是mock数据");
setState((prev) => ({ ...prev, isMock: true }));
}
// 从响应中提取详细赔率数据(排除isMock字段)
const { isMock, ...oddsData } = oddsResponse.data;
// 使用matchId更新数据
const newData = [...state.list];
for (let i = startIndex; i < pageSize * currentPage; i++) {
const match = state.list[i];
if (oddsData[match.matchId] && state.list[i]) {
newData[i] = {
...match,
...oddsData[match.matchId],
};
}
}
setState(
produce(prev, (draft) => {
draft.list = newData;
})
)
}
} catch (error) {
console.error("获取详细赔率失败:", error);
}
};
问题在于loadCurrentPageOdds
中直接取state.list还是空数组,而且setState的时候只更新了list,没有更新page,就会导致翻页无效。
通常解决方案就是通过传参 await loadCurrentPageOdds(response.data.list, 1, 10);
但是翻页也要调用这个函数的
还有就是把list
单独提出来, const [list, setList] = useState<NFootball.IFootballMatch[]>([]);
。
也可以通过传递函数的方式来缓解,但是依旧无法解决形参传递问题
ini
setState(pre=>({...pre,...list}))
也可以和produce结合
ini
setState(pre=>produce(pre,draf=>{
}))
这种方式我真的太久没有了,可能觉得produce已经完全替代了...
在通过loadData
调用loadCurrentPageOdds
时
javascript
setState(pre=>{
console.log(pre)
return pre
})
console.log(state.list)
前者打印的是改变后的数据,后者打印一个空数组
那么一道经典的面试题
scss
const [count, setCount] = useState<number>(1);
<Button
onClick={() => {
setCount(count + 1);
setCount(count + 1);
setCount(count + 1);
}}
>
点击{count}
</Button>
问:每次点一次加几,答案:加1 问:如何不改变setCount数量做到每次点一次加3,答案:
javascript
setCount((pre) => pre + 1);
setCount((pre) => pre + 1);
setCount((pre) => pre + 1);
但说实话,大部人会有下意识的想到,进阶版面试题可以从上面的例子中演化出来。
比如能不去掉 await loadCurrentPageOdds(response.data.list, 1, 10);
第一个形参
我试了下,最后只能尝试把所有逻辑都写进setState里,但是因为有接口调用,还是不行