React中的props、state和ref
React 中三类核心数据来源的职责差异与判断边界。
#frame
#react
#synthesis
#growing
[!info] related notes
- 所属 MOC: React MOC
- 上位主题: React
- 相关概念: useState, useRef, useContext
React中的props、state和ref
很多 React 代码之所以会越写越乱,不是因为组件太多,而是没有分清 props、state 和 ref 各自该管什么。
一句话定义
props:外部传入的数据state:组件内部、且会影响渲染的记忆ref:组件内部、但不参与渲染的可变值
props 管什么
- 父组件给子组件的输入
- 展示内容、行为配置、回调函数等
- 本质上是“组件从外界接收什么”
state 管什么
- 组件自己需要记住的值
- 这些值变化后会重新影响 UI
- 通常由
useState或useReducer管理
例如:
- 输入框内容
- 当前选中项
- 弹窗是否打开
- 加载中 / 失败 / 成功状态
ref 管什么
- DOM 引用
- 定时器 ID
- 某个实例对象
- 上一次渲染值
它们的共同点是:需要记住,但变化后不需要重新渲染界面。
例如:
inputRef.currenttimerRef.currentpreviousValueRef.current- 第三方实例对象
一个最实用的判断题
每次面对一个值时,先问三件事:
- 它是不是父组件给我的?如果是,多半是
props - 它变化后要不要更新界面?如果要,多半是
state - 它只是想被记住,但不驱动渲染吗?如果是,多半是
ref
为什么这件事特别重要
很多 React 代码越写越乱,不是因为 Hook 太多,而是因为把三种不同角色混到了一起。
典型错误有:
- 本该直接从
props读取,却又复制一份到state - 本该进入
state的值,被偷偷塞进ref - 本该放在普通局部变量里的临时值,被误建成
state
一个常见反例
function UserCard({ user }: { user: { name: string } }) {
const [name, setName] = useState(user.name)
return <div>{name}</div>
}
如果这里只是展示 user.name,那这份 state 很可能是多余的。因为它把外部输入复制成了内部状态,后续同步边界会变复杂。
常见误区
- 把本该进
state的数据藏进ref - 把只用于内部临时计算的值提升成
state - 直接修改
props
最短记忆方式
props 是输入,state 是会驱动 UI 的内部记忆,ref 是不会驱动 UI 的内部记忆。
学习检查
不看正文回答:
- props、state、ref 分别对应“外部输入”“驱动 UI 的内部记忆”“不驱动 UI 的内部记忆”中的哪一类?
- 为什么把 props 无条件复制进 state 往往会制造同步问题?
- 什么值适合放 ref 而不适合放 state?
- 如果一个值变化后必须刷新界面,却被放进 ref,会出现什么现象?
- 普通局部变量与 ref 的差别是什么?
- 给一个表单组件,分别举出一个 props、state 和 ref 的合理例子。