对useState加深了理解
前言
一直以来的疑问,使用useState的管理的状态可以不通过setState修改,而直接修改值嘛?
我长期理解的都是不能对state直接做更改.因为useState
返回的state
是一个不可变对象,直接修改它不会更新组件的状态。
这点我是牢牢的记住的,但是我一直也有个疑问,如果管理的状态值是个object
, 直接对对象本身做操作,直接修改原对象,值会得到更改(如push
, pop
, shift
, unshift
, splice
等)嘛?
虽然有这个疑问,但是我没有去验证它,因为这只是偶尔在脑海里闪过的问题。于是在多年的开发中,我都是默认只使用setState
这一种途径去更改状态值
契机
下面是一段ai生成的代码,作用是确保异步函数多次调用时,也能按照顺序执行,并返回最后一次调用的结果。
/**
* useSequentialPromise Hook
* 确保异步函数按照顺序执行,并返回最后一次调用的结果。
* @param asyncFunction 异步函数,接受任意参数并返回Promise
*/
function useSequentialPromise<T>(
asyncFunction: (...args: any[]) => Promise<T>,
) {
const [lastResult, setLastResult] = useState<T | null>(null);
const [lastError, setLastError] = useState<Error | null>(null);
const [queue, setQueue] = useState<((...args: any[]) => Promise<T>)[]>([]);
const [isRunning, setIsRunning] = useState(false);
useEffect(() => {
let cancelled = false;
async function processQueue() {
while (queue.length > 0 && !cancelled) {
setIsRunning(true);
try {
/** 纠正了我一个误区,useState管理的状态量也是可以修改的 */
const currentFunction = queue.shift()!;
const result = await currentFunction();
if (!cancelled) {
setLastResult(result);
setLastError(null);
}
} catch (error) {
if (!cancelled) {
setLastResult(null);
setLastError(error as Error);
}
} finally {
setIsRunning(false);
}
}
}
if (queue.length > 0) {
processQueue();
}
return () => {
cancelled = true;
};
}, [queue]);
const enqueueFunctionCall = (...args: Parameters<typeof asyncFunction>) => {
const wrappedFunction = async () => await asyncFunction(...args);
setQueue((prevQueue) => [...prevQueue, wrappedFunction]);
};
return { lastResult, lastError, isRunning, enqueueFunctionCall };
}
对ai生成的代码进行code check时,我发现这段代码没有调用setQueue
进行队列的衰减,取而代之的是使用了queue.shift()!;
,这会减少队列的成员嘛?经过测试,queue确实减少。useEffect
也能监听到queue的变更。
也就是说在原数组上进行操作,修改了数组的结构,导致数组的引用发生了变化时,React 检测到状态变化,并在下次渲染时使用新的数组值
看来useState
只是阻止直接对字面量类型更改,直接修改对象类型的成员值是可以的
收获
对useState加深了理解,虽然在之后的开发中,我依然会使用setState
去修改状态值,确保React能正确地追踪状态变化
但是类似上面的这个hook案例,我也不介意使用这个特性去少写两行代码。。。
感谢阅读!
转载自:https://juejin.cn/post/7373590621246832659