熟悉 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 写作) 欢迎围观~

有意请私聊我~

相关推荐
小钊(求职中)4 小时前
Java开发实习面试笔试题(含答案)
java·开发语言·spring boot·spring·面试·tomcat·maven
小小码农(找工作版)4 小时前
JavaScript 前端面试 4(作用域链、this)
前端·javascript·面试
CDwenhuohuo6 小时前
使用 NVM 随意切换 Node.js 版本
node.js
uhakadotcom6 小时前
约束求解领域的最新研究进展
人工智能·面试·架构
随风起舞17 小时前
node.js里的bind,apply, call的区别是什么
前端·javascript·node.js
超爱吃士力架8 小时前
MySQL 三层 B+ 树能存多少数据?
java·后端·面试
超爱吃士力架8 小时前
MySQL 索引的最左前缀匹配原则是什么?
java·后端·面试
LiuMingXin8 小时前
埋头苦干Vue3项目一年半,总结出了16个代码规范
前端·vue.js·面试
神秘代码行者8 小时前
Node.js Buffer 教程
javascript·node.js
Eamonno10 小时前
深入理解React性能优化:掌握useCallback与useMemo的黄金法则
react.js·性能优化