熟悉 React 原理,却答不对这道简单的 setState 面试题

开始

大家好,我是双越老师~

最近春季招聘季节,好多同学找我 1v1 前端面试咨询,咨询服务包括 1v1 模拟面试环节。对于 React 技术栈的同学,我会问下面这道问题。

我觉得这是一个非常基础的 setState 应用问题,但 80% 的同学却回答错误,甚至他们都了解或者熟悉 React 原理,甚至看过源码。

PS:我正在开发一个 Node 全栈 AIGC 知识库项目 划水AI ,仿 Notion AI 和协同编辑,如果想一起加入项目开发团队,可私信我~

为面试而背原理

React 原理很多人都能说上一些,什么 JSX、虚拟 DOM、diff 算法、fiber、并发模式、合成事件 ......

社区里也满是这种资料,焦虑你我他,卷不完继续卷,为了面试造火箭。完全没有自己的思考和分析。

例如:为何 React 需要 fiber 并发模式这一套复杂东西,而 Vue 不需要呢?Vue 性能也不差呀。React 是故意弄这一套来为难自己吗?------ 当然不是,肯定是有原因的。

不过,这是个题外话,我们还是先看看这个 setState 面试题吧。

题目

如下代码是一个 React 组件。提问:

  • 初次渲染这个组件,控制台会打印什么,组件的 <span>{value}</span> 显示什么值?
  • 然后点击 increase 按钮,控制台会打印什么,组件的 <span>{value}</span> 显示什么值?
js 复制代码
function Demo() {
  console.log('hello')

  const [value, setValue] = useState(100)
  function clickHandler() {
    setValue(value + 1)
    setValue(value + 1)
    console.log('value1 ', value)
    setValue((value) => value + 1)
    setValue((value) => value + 1)
    console.log('value2 ', value)
  }
  return (
    <div>
      <span>{value}</span>
      <button onClick={clickHandler}>increase</button>
    </div>
  )
}

初次渲染

这一步大家都知道,最后显示的值是 100 ,没有回答错误的。

但是,绝大部分人会忽略掉一开始的 console.log('hello') 完全无视。程序员要严谨,每一行代码都要读,而且题目已经明确提问了"控制台会打印什么"。

经过我的提示以后,大家才意识到原来还要打印 'hello' ------ 但是,'hello' 打印几次呢?

重复渲染

React18 开发环境下,组件渲染时会被执行两次,这是为了更早的验证组件完整的生命周期。生产环境下不会重复渲染。这个知识点很多同学都不知道,虽然他们也是 React 技术栈的。

所以,'hello' 会被打印两次。哪怕是在 useEffect 中,也是会被打印两次

js 复制代码
function App() {
  console.log('hello')
 
  useEffect(() => {
    console.log('hello 100')
  })

但,这个不是该题目的重点,即便你不知道这个知识点,只说打印一次 'hello' ,我觉得也还可以。继续往下看。

异步更新 state

继续第二步,点击 increase 按钮,value1value2 分别打印什么?大部分人的答案是

value1 101
value2 103

答案当然是错误的,正确答案是 value1value2 全都打印 100 。不管 Vue 还是 React 它们都是异步更新异步渲染的,同步代码中无法获得最新的值。

不过值得肯定的是,大部分知道 setValue(value + 1) 会合并更新,而 setValue(v => v + 1) 不会合并更新。所以最后页面显示的值是 103

还没结束

所有同学到这里都以为结束了,无一例外。

直到我追问:'hello' 还会打印吗?这才引发一少部分同学的思考,他们意识到 React 组件更新了,函数要重新执行。

然后我继续追问:'hello' 会在什么时机打印呢?会在 'value2' 之前还是之后呢?

这又引起了同学的纠结,不知道什么时机,甚至不知道 'hello' 还会在打印几次。于是有了各种答案:

  • 'value1' 之后打印一次,在 'value2' 之后再打印一次
  • 'value2' 之前打印一次
  • 'hello' 还有打印 3 次,因为之前有 state 合并,不是 4 次
  • (答案太多我也记不清了)

其实答案很简单:如果不考虑 React18 这个重复渲染,'hello' 打印一次,如果考虑就打印两次。

我觉得这俩答案都可以,因为我们工作中写代码一般会封装在 useEffect 中,不会有这个问题。

分析整个过程

PS:为了简化流程,不考虑 React18 重复渲染的现象。

第一,组件初次渲染

  • 执行函数
  • 打印 'hello'
  • 定义 value100
  • 定义 clickHandler 函数,但未执行,且不管它(未执行的函数,就当作一个黑盒,不管)
  • 返回 UI ,值是 100

第二,点击按钮

  • 执行 clickHandler 函数
  • 执行两步 setState 但异步更新
  • 打印 value1 100
  • 执行两步 setState 但异步更新
  • 打印 value2 100

第三,state 变化触发组件更新

  • 执行函数
  • 打印 'hello'
  • 定义 value103 ------ 【注意】到这一步才获取到最新的 state
  • 定义 clickHandler 函数 ------ 是的,重复定义了,如不想重复请用 useCallback
  • 返回 UI ,值是 103

答案

如下图

和我一起开发 React 全栈项目

学了 React 但没有真实项目实践经验?简历上写的项目太简单?

来跟我一起做一个 React Next.js Node 全栈 AIGC 项目 划水AI,仿 Notioin AI 和协同编辑

项目介绍可以看这里 前端转全栈: Next.js + ChatGPT 开发 AIGC 知识库(AI 写作) 欢迎围观~

有意请私聊我~

相关推荐
小飞猪Jay35 分钟前
C++面试速通宝典——13
jvm·c++·面试
丁总学Java5 小时前
微信小程序-npm支持-如何使用npm包
前端·微信小程序·npm·node.js
睡觉然后上课6 小时前
c基础面试题
c语言·开发语言·c++·面试
xgq6 小时前
使用File System Access API 直接读写本地文件
前端·javascript·面试
看到请催我学习7 小时前
如何实现两个标签页之间的通信
javascript·css·typescript·node.js·html5
邵泽明8 小时前
面试知识储备-多线程
java·面试·职场和发展
夜流冰9 小时前
工具方法 - 面试中回答问题的技巧
面试·职场和发展
zqx_710 小时前
随记 前端框架React的初步认识
前端·react.js·前端框架
NiNg_1_23411 小时前
npm、yarn、pnpm之间的区别
前端·npm·node.js
余生H12 小时前
前端的全栈混合之路Meteor篇:关于前后端分离及与各框架的对比
前端·javascript·node.js·全栈