likes
comments
collection
share

对useState加深了理解

作者站长头像
站长
· 阅读数 64

前言

一直以来的疑问,使用useState的管理的状态可以不通过setState修改,而直接修改值嘛?

我长期理解的都是不能对state直接做更改.因为useState返回的state是一个不可变对象,直接修改它不会更新组件的状态。

这点我是牢牢的记住的,但是我一直也有个疑问,如果管理的状态值是个object, 直接对对象本身做操作,直接修改原对象,值会得到更改(如pushpopshiftunshiftsplice等)嘛?

虽然有这个疑问,但是我没有去验证它,因为这只是偶尔在脑海里闪过的问题。于是在多年的开发中,我都是默认只使用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
评论
请登录