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

有意请私聊我~

相关推荐
donecoding9 小时前
一个 sudo 引发的血案:npm 全局包权限错乱彻底修复
前端·node.js·前端工程化
许彰午9 小时前
我手写了一个 Java 内存数据库(二):B+ 树的插入与分裂
java·开发语言·面试
weisian15114 小时前
基础篇--概念原理-2-参数是什么?——从原理到实战,一篇讲透
面试·职场和发展·模型参数·7b和70b·参数=规则,不是原始数据
AI人工智能+电脑小能手15 小时前
【大白话说Java面试题】【Java基础篇】第26题:Java的抽象类和接口有哪些区别
java·开发语言·面试
donecoding17 小时前
别再让 pnpm 跟着 nvm 跑了!独立安装终极指南
前端·node.js·前端工程化
逻辑驱动的ken17 小时前
Java高频面试考点场景题20
java·开发语言·深度学习·面试·职场和发展
Wect18 小时前
深度剖析浏览器跨域问题
前端·面试·浏览器
前端之虎陈随易19 小时前
有生之年系列,Nodejs进程管理pm2 v7.0发布
前端·typescript·npm·node.js
刀法如飞19 小时前
Java数组去重的20种实现方式——指导AI解决不同问题的思路
java·算法·面试
ayqy贾杰19 小时前
Cursor SDK发布!开发者可直接搬走其内核
前端·vue.js·面试