获取中...

-

Just a minute...

令人困扰的问题

是因为异步吗

大家都知道,react的useState和useReducer,在set和dispatch之后,马上去获取值,是拿不到最新的值的。这个原因之一是useState和useReducer是异步更新的,也就是说我们刚调用完set和dispatch马上去取值,这种同步代码执行的时候,状态还没更新呢,所以拿不到。

同步如何

那我们如果换成redux呢?redux不使用中间件扩展的话,全部都是同步的操作,也就是说你上面一行dispatch之后,马上状态的更新就完成了。但是其实我们马上去获取,也是拿不到最新的状态的。其根本原因是React的机制。

React的理念和机制

React的快照理念,导致了上述的问题。我们就拿React的函数组件来举例子,我们知道函数组件所谓的渲染就是执行一遍自己,所以组件重新渲染就会重新执行这个函数。那我们定义过的变量也就会被重新定义,也就是说,当你写const [value,setValue] = useState(0)的时候,每次函数重新渲染,value都被重新定义了一遍,并且被重新赋了值。这就是value虽然是const,但是仿佛能被改变值的原因。

React的理念如此,页面是某个状态的快照,状态和页面是一一对应的。状态变了,就要重新渲染。而组件每次重新渲染,都对应着一个新的状态,新的状态和旧的状态是完全隔离的,打个比方就像平行宇宙一样。每次重新渲染,就分出来一个平行宇宙。两个平行宇宙的你,可能相似,但不是一个人。

也就是说,更新后的状态,只存在于新的平行宇宙里。你setValue之后,再去获取value,获取的还是老的value。新的value值已经在下一次执行了,需要下一次渲染才能拿到了,所以这样是必定拿不到更新后的值的。

如何能拿到更新后的值

一种方法是使用useEffect。当每次函数重新渲染后,都会执行useEffect,这个时候你是正处在新一次函数执行中的,所以是能拿到新定义的value值的。但是这样有个问题,就是如果useState的变量是个引用值,然后你要监听的是引用值里面的某个属性,当这个属性变化的时候去更改另一个属性,这样就会导致函数无限重新渲染。比如

1
const [obj,setObj] = useState{a:0,b:1}

我想做的是,每当obj.b变化的时候,我要去更新obj.a的值。我们首先不能直接obj.a=xxx这样去做,肯定要setObj(newObj)这样去更改a的值,这就会导致我们监听的是obj,但是又会改obj的值,这时候这种方法就行不通了。

另一种方法借助useRef。useRef很特殊,返回一个带current属性的对象。每次重新渲染,函数组件都重新执行,但是useRef不会被重新定义,一直是最初的那个变量。因此useRef相当于是可以跨越不同平行宇宙的存在。我们可以将新的变量值赋给useRef,然后就能拿到新的值了。

我们可以封装一个自己的hook:

1
2
3
4
5
6
7
8
9
10
const useGetState = (initialState) => {
const [state, setState] = useState(initialState);
const ref = useRef(initialState);
const syncSetState = useCallback((newValue) => {
ref.current = newValue;
setState(newValue);
}, []);
const getState = useCallback(() => ref.current);
return [state, syncSetState, getState];
};

我们可以通过第三个返回值,来即刻拿到更新后的值。就先说这么多吧,困了,我恨加班

相关文章
评论
分享
  • 动手实现react-ssr 2

    仓库链接:本篇代码 运行方法参考readme,请使用pnpm,因为本次使用的rspack尚未推出1.0版本,预计后续可能会有很多breakchange,所以lock文件至关重要,而我只上传了pnpm的lock,非常抱歉。 环境:no...

    动手实现react-ssr 2
  • 动手实现react ssr

    关于ssr相关的介绍,可以移步之前的一篇博文,本文不再赘述 日常工作中,我们可能都接触过ssr,不过我们可能通常是借助于框架(例如Next.js)的支持来完成ssr。今天我想尝试,摆脱高度封装的前端框架,只依赖react相关的库,来实...

    动手实现react ssr
  • 基于tapable来模拟webpack插件机制

    前两天看到ByteFE公众号发了篇文章,从源码去讲webpack。我之前也从很多方面去学习webpack,只是源码一直没太看得进去,这一次我想仔细地读一读。 简要介绍tapable说实话,之前看webpack源码一直没看的太懂,...

    基于tapable来模拟webpack插件机制
  • 深入js——作用域,作用域链,执行栈(一)

    最近在补js基础。当初自学js的时候,总是感觉学的不扎实。只能说不去上手,再怎么死读书,也理解不了。积累了经验,然后自己去思考,这个时候再去看理论,就容易理解了。 感觉工作一年以来,确实学到了很多,但是过于专注于应用方面的知识,反倒...

    深入js——作用域,作用域链,执行栈(一)
  • webpack运行时代码简要分析

    开个坑,主要也是怕自己后面忘了 简单写写,有空了补上 __webpack_modules是一个数组,每个元素都是一个函数,函数接受三个参数:第一个参数module好像没用到,第二个是一个对象(会把本模块要导出的属性,赋值给这个对象),...

    webpack运行时代码简要分析
  • webpack动态加载原理简述

    为什么需要动态加载上一篇讲我写webpack针对markdown的loader的时候,提到了希望能动态加载以优化性能。篇幅原因没有展开说,打算单独写一篇文章讲一下。 当我们访问网站的时候,浏览器会向服务器请求页面资源。首先请求的当然是...

    webpack动态加载原理简述
  • 编写一个简单的webpack loader的踩坑

    因为觉得hexo框架搭的博客功能一般,就有了想要自己写一个博客的想法。然后就想着如果把markdown文件也放到项目里的话,会比较方便,发现需要编写一个加载markdown的loader,于是就有了这篇博客,来记录一下踩过的坑和收获...

    编写一个简单的webpack loader的踩坑
  • 简单通俗解释HTTP缓存

    开始前的碎碎念 最近加班真的很严重,组里同事们都已经苦不堪言。业务交付压力非常大,根本没时间去磨练本领,学习技术。真的很讨厌这种没有成长的日子,每天被业务需求赶着跑。每天下班之后,本来应该用于提升自我的时间也被压榨用来写业务代码。 ...

    简单通俗解释HTTP缓存
  • 从invalid hook call报错说到npm install相关

    遇到了invalid hook call报错上周,业务下游的同事反馈了一个生产问题,说我们传的值有问题,领导让我帮忙排查一下。我最近一直没做那个项目相关的需求,打开那个项目切到release分支,拉代码,npm i然后启动,结果就白屏...

    从invalid hook call报错说到npm install相关
  • 发布一个npm包的踩坑

    试着自己发布了一个npm包,记录一下自己踩的坑 package.json首先npm init,然后添加type:module字段,将其定义为一个es6模块。然后在files字段设置要发布上去的内容,比如dist文件夹。 接下来将开发用...

    发布一个npm包的踩坑
Please check the parameter of comment in config.yml of hexo-theme-Annie!