目录
[1. useState(getArr) vs useState(getArr())](#1. useState(getArr) vs useState(getArr()))
[2. 数组的不可变更新](#2. 数组的不可变更新)
说明

代码示例
javascript
import React, { FC, useState } from 'react'
/**
* 模拟一个昂贵的计算函数
*
* 这个函数的作用是创建并填充一个长度为 100 的数组。
* 我们在函数内部打印日志,是为了观察它被调用的时机。
*/
function getArr() {
// 只有当 getArr 被执行时,控制台才会打印 'getArr...'
// 这帮助我们理解 useState 传参的执行机制
console.log('getArr...')
// 创建一个长度为 100 的空数组
const arr = new Array(100)
// 将数组的每一个元素填充为字符串 'hello'
arr.fill('hello')
// 返回填充好的数组
return arr
}
/**
* React 函数组件 Demo
*
* 该组件演示了:
* 1. useState 的惰性初始化(传入函数)
* 2. 不可变数据更新(展开运算符)
*/
const Demo: FC = () => {
// 每次组件渲染(重新执行)时,都会打印 'demo...'
console.log('demo...')
// --- 状态定义 ---
// useState 接收一个函数 getArr 作为参数。
// 这是"惰性初始化"的写法。
// React 会执行 getArr(),将其返回值作为 arr 的初始值。
// 关键点:getArr 只会在组件的**首次渲染**时执行,后续重新渲染组件时,该函数不会再次执行。
const [arr, setArr] = useState(getArr)
// --- 事件处理函数 ---
// 点击按钮时触发
function addStr() {
// 1. 使用展开运算符 (...) 复制原数组 arr 的所有元素
// 2. 在新数组末尾添加一个新元素 'hello'
// 3. 使用 setArr 更新状态
// 注意:不能直接修改原数组 arr.push(),必须返回一个新数组来触发视图更新
setArr([...arr, 'hello'])
}
// --- JSX 渲染结构 ---
return (
<>
{/* 显示当前数组的长度 */}
<p>length: {arr.length}</p>
{/* 包含操作按钮的容器 */}
<div>
{/* 点击按钮调用 addStr 函数 */}
<button onClick={addStr}>add</button>
</div>
</>
)
}
export default Demo
结果:getArr函数,只在初始化的时候,执行一次

用法解释
1. useState(getArr) vs useState(getArr())
代码中使用的是 useState(getArr)(传入函数引用),而不是 useState(getArr())(传入函数执行结果)。
useState(getArr)(当前代码):- 机制: 惰性初始化。
getArr函数只会在组件第一次渲染 时执行一次,用来计算初始 state。之后即使组件因为状态更新而重新渲染,getArr也不会再执行。 - 适用场景: 当初始 state 需要通过昂贵的计算(如创建大数组、复杂计算)才能获得时,使用这种方式可以优化性能。
- 机制: 惰性初始化。
useState(getArr()):- 机制: 每次组件渲染(重新执行)时,都会先执行
getArr()函数,然后将结果传给useState。这会导致不必要的重复计算。
- 机制: 每次组件渲染(重新执行)时,都会先执行
2. 数组的不可变更新
在 addStr 函数中,使用了 [...arr, 'hello']:
- 原因: React 中的状态(State)是不可变的。如果你直接使用
arr.push('hello')修改原数组,数组的引用地址没有变,React 会认为状态没有变化,从而不会触发视图重新渲染。 - 解决: 使用展开运算符
...创建一个新数组,setArr接收到新的引用地址,从而触发组件更新。