React 三个重要概念:Ref、Props、State 详解

React 三个重要概念:Ref、Props、State 详解

在 React 中,propsstateref 都非常重要。

可以简单理解为:

名称 作用 修改后是否重新渲染
props 父组件传递给子组件的数据 通常会
state 组件内部管理的数据
ref 获取 DOM 或保存可变数据 不会

一、props:组件之间传递数据

props 是父组件传递给子组件的数据。

1. 基本使用

jsx 复制代码
function Parent() {
  return <Child name="小明" age={18} />
}

function Child(props) {
  return (
    <div>
      姓名:{props.name}
      <br />
      年龄:{props.age}
    </div>
  )
}

也可以直接解构:

jsx 复制代码
function Child({ name, age }) {
  return (
    <div>
      姓名:{name}
      <br />
      年龄:{age}
    </div>
  )
}

2. 传递不同类型的数据

jsx 复制代码
function Parent() {
  const user = {
    name: '小明',
    age: 18
  }

  return (
    <Child
      name="小明"
      age={18}
      isStudent={true}
      user={user}
    />
  )
}

注意:

jsx 复制代码
name="小明"

传递的是字符串。

jsx 复制代码
age={18}
isStudent={true}
user={user}

花括号中可以传递数字、布尔值、变量、对象、数组或函数。

3. props 是只读的

子组件不应该直接修改 props

jsx 复制代码
function Child(props) {
  // 不推荐这样做
  props.name = '小红'

  return <div>{props.name}</div>
}

props 应该由父组件负责修改。如果子组件想通知父组件,可以通过回调函数:

jsx 复制代码
import { useState } from 'react'

function Parent() {
  const [message, setMessage] = useState('')

  return (
    <div>
      <p>{message}</p>
      <Child onSend={setMessage} />
    </div>
  )
}

function Child({ onSend }) {
  return (
    <button onClick={() => onSend('子组件传来的消息')}>
      发送消息
    </button>
  )
}

4. children 属性

组件标签中嵌套的内容,会通过 children 属性传递:

jsx 复制代码
function App() {
  return (
    <Card>
      <p>这是卡片内容</p>
    </Card>
  )
}

function Card({ children }) {
  return <div className="card">{children}</div>
}

二、state:组件内部的数据

state 是组件内部自己管理的数据。

state 发生变化时,React 会重新渲染组件。

1. 基本使用

jsx 复制代码
import { useState } from 'react'

function Counter() {
  const [count, setCount] = useState(0)

  function handleClick() {
    setCount(count + 1)
  }

  return (
    <button onClick={handleClick}>
      点击次数:{count}
    </button>
  )
}

这段代码中:

jsx 复制代码
const [count, setCount] = useState(0)

表示:

  • count:当前状态值
  • setCount:修改状态的方法
  • 0:状态初始值

2. 不要直接修改 state

错误写法:

jsx 复制代码
count = count + 1

正确写法:

jsx 复制代码
setCount(count + 1)

修改对象或数组时,也要创建新的对象或数组:

jsx 复制代码
const [user, setUser] = useState({
  name: '小明',
  age: 18
})

setUser({
  ...user,
  age: 19
})

修改数组:

jsx 复制代码
const [list, setList] = useState([])

setList([
  ...list,
  '新数据'
])

3. 根据旧值修改 state

如果新状态依赖旧状态,推荐使用函数形式:

jsx 复制代码
setCount(prevCount => prevCount + 1)

例如:

jsx 复制代码
function handleClick() {
  setCount(prev => prev + 1)
  setCount(prev => prev + 1)
}

这样可以确保状态基于最新值进行更新。

4. state 的特点

state 通常用于保存:

  • 输入框的内容
  • 计数器的数字
  • 是否显示弹窗
  • 当前选中的菜单
  • 商品数量
  • 加载状态
  • 列表数据

只要数据变化后需要更新页面,就应该考虑使用 state


三、ref:获取 DOM 或保存可变数据

ref 主要有两个用途:

  1. 获取 DOM 元素
  2. 保存一个变化后不需要重新渲染页面的数据

1. 获取 DOM 元素

jsx 复制代码
import { useRef } from 'react'

function App() {
  const inputRef = useRef(null)

  function handleFocus() {
    inputRef.current.focus()
  }

  return (
    <div>
      <input ref={inputRef} />

      <button onClick={handleFocus}>
        聚焦输入框
      </button>
    </div>
  )
}

执行过程:

  1. useRef(null) 创建一个 ref 对象。
  2. ref={inputRef} 绑定到输入框。
  3. 输入框 DOM 元素会保存到 inputRef.current
  4. 调用 inputRef.current.focus() 让输入框获得焦点。

2. ref 保存可变数据

jsx 复制代码
import { useRef } from 'react'

function App() {
  const countRef = useRef(0)

  function handleClick() {
    countRef.current += 1
    console.log(countRef.current)
  }

  return <button onClick={handleClick}>点击</button>
}

修改 countRef.current 不会触发组件重新渲染。

3. State 和 Ref 的区别

如果数据变化后需要显示到页面上,使用 state

jsx 复制代码
const [count, setCount] = useState(0)

如果数据变化后不需要更新页面,使用 ref

jsx 复制代码
const countRef = useRef(0)

例如:

  • 页面上的计数器:使用 state
  • 保存定时器 ID:使用 ref
  • 输入框自动聚焦:使用 ref
  • 保存上一次的值:可以使用 ref

四、props、state 和 ref 的区别

Props

jsx 复制代码
<Child name="小明" />

特点:

  • 来自父组件
  • 子组件只能读取,不能直接修改
  • 用于组件之间传递数据

State

jsx 复制代码
const [count, setCount] = useState(0)

特点:

  • 由组件自己管理
  • 使用 setter 修改
  • 修改后会触发重新渲染
  • 用于保存页面需要显示的数据

Ref

jsx 复制代码
const inputRef = useRef(null)

特点:

  • 可以获取 DOM 元素
  • 可以保存可变数据
  • 修改 .current 不会触发重新渲染
  • 适合操作 DOM、保存定时器等数据

五、实际开发中如何选择

可以按照下面的方式判断:

text 复制代码
父组件传给子组件的数据      使用 props
组件内部需要显示的数据        使用 state
需要操作 DOM 元素             使用 ref
数据变化但不需要刷新页面       使用 ref

例如:

jsx 复制代码
function App() {
  const inputRef = useRef(null)
  const [text, setText] = useState('')

  return (
    <div>
      <input
        ref={inputRef}
        value={text}
        onChange={event => setText(event.target.value)}
      />

      <p>输入内容:{text}</p>

      <button onClick={() => inputRef.current.focus()}>
        聚焦输入框
      </button>
    </div>
  )
}

这段代码中:

  • textstate,因为它需要显示在页面上。
  • inputRefref,因为它用于操作输入框 DOM。
  • 如果把数据传给子组件,就会使用 props

六、总结

React 中的三个重要概念可以这样记忆:

text 复制代码
props:父组件传给我的数据
state:我自己管理,并且会影响页面的数据
ref:我想直接操作 DOM 或保存数据,但不想触发重新渲染

最简单的判断方法是:

页面要不要随着数据变化而更新?

如果需要,使用 state;如果不需要,可以考虑使用 ref

相关推荐
心易行者3 分钟前
Python在线运行+SQLite数据库实战:0成本搭个人数据后台,5个场景直接套用
前端·网络·人工智能·python
@tangguo12319 分钟前
npm 和 yarn 配置说明
前端·javascript·npm·node.js·yarn
zhiyouTech21 分钟前
GEO实战:把生成式引擎优化当成检索工程来做(含五断点诊断与50题Benchmark)
前端·人工智能
志尊宝41 分钟前
Vue3 零基础每日笔记(052):路由常见坑一次排雷——404、刷新丢参数、部署白屏
前端·javascript·vue.js·笔记·html5
linux_cfan43 分钟前
videojs v10 源代码系列解读:13 · 能力型媒体契约:`Media` 的组合接口
前端·javascript·音视频
涛涛ing1 小时前
2026年9月,前端圈同时发生了四件事,指向同一个方向
前端
艾伦野鸽ggg1 小时前
Vue2 模板语法与样式绑定
前端
Amos_Web1 小时前
Rspack 源码解析(十一):资产 Hook 与增量构建
前端·rust·源码阅读
PC2005_cloud1 小时前
Windows 数据使用量页面卡死:1097 个热点档案和 161 MB 的 SRUM 库
前端·后端
烈风逍遥1 小时前
AI大模型中fetch 和 ReadableStream为啥一起出现
前端·人工智能