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

相关推荐
weixin_431600441 小时前
前端对接 SSE 的两种常见方式
前端·后端·学习·ai·sse·nest.js
Mh1 小时前
如何使用GSAP实现一个 `pinned` 滚动楼层叙事?
前端·javascript·css
Larcher7 小时前
React Router 不只是页面跳转:从 SPA 路由到权限守卫的完整实践
javascript·后端
Larcher7 小时前
大模型为什么每次回答都不一样?一文搞懂 Temperature、Top K 与 Top P
javascript·后端
用户9385156350710 小时前
从零在浏览器里跑 DeepSeek-R1:WebGPU + Transformer.js 全链路实战
前端·设计模式·typescript
CodeSheep10 小时前
稚晖君公司人事大变动,来了!
前端·后端·程序员
鱼樱前端11 小时前
用 AI 做内容变收入
前端·人工智能·ai编程
eric-sjq11 小时前
10 分钟实战:用 0.6B 本地模型生成中文网页(WanlyFrontend + 编译器全流程)
javascript·机器学习·自然语言处理·html
浮生望11 小时前
React + TypeScript 组件设计进阶:从类型约束到无状态组件的三次进化
前端