探讨:围绕 props 阐述 React 通信

在 ++✓ 🇨🇳 开篇:通过 state 阐述 React 渲染++ 中,以 setInterval 为例,梳理了 React 渲染的相关内容。

📢 本篇会 ++✓ 🇨🇳 围绕 props 阐述 React 通信++

props

React 组件使用 props 来互相通信。每个父组件都可以提供 props 给它的子组件,从而将一些信息传递给它。

html 复制代码
<Avatar
  name="ligang" 
  address={<span>山东省</span>}
  size={100}
/>

也可以拆分组件,将子组件作为 JSX 传递。

将 JSX 作为子组件传递
html 复制代码
<Avatar
  name="ligang" 
  size={100}>
  <span>山东省</span>
</Avatar>

上述 Avatar 组件将接收一个被设为 <span>children prop 。

javascript 复制代码
function Card({ children }) {
  return (
    <>{children}</>
  );
}

注意! 需要区分 childrenChildren

‼️ 在 React 中,children 属性是被视为 不透明的 数据结构。这意味着你不应该依赖它的结构。如果要转换,过滤,或者统计子节点,你应该使用 Children 方法。

实际操作过程中,children 在底层常常被表示为数组。但是如果这里只有一个子节点,那么 React 将不会创建数组,因为这将导致不必要的内存开销。 只要你使用 Children 方法而不是直接操作 children 底层结构,即使 React 改变了 children 数据结构的实际实现方式,你的代码也不会被中断。

语法 含义
Children.count(children) 可以获取 children 中的节点数量
Children.forEach(children, (child, index) => {}); 为每个 children 中的每个子节点执行一段代码
Children.map(children, child => {}, thisArg?) children 中的每个子节点进行映射或转换
Children.only(children) 断言 children 代表一个 React 元素
Children.toArray(children) 通过 children 创建一个数组

☔️ Children 使得错误排查变得较为困难,推荐使用 替代方案[1](#1) 而不是使用 Children

组件是否由 props 驱动,可以分为受控&非受控组件。

受控&非受控

当组件中的重要信息是由 props 而不是其自身状态驱动时,就可以认为该组件是 "受控组件" ;受控组件具有最大的灵活性,但它们需要父组件使用 props 对其进行配置。

javascript 复制代码
export default function Input ({value, onChange}) {
  return (
  	<input 
    	value={value} 
			onChange={e => {onChange(e.target.value)}}
    />
  )
}

当组件中的重要信息是由其自身状态 state驱动时,就可以认为该组件是 "非受控组件";非受控组件通常很简单,因为它们不需要太多配置。

javascript 复制代码
export default function Input () {
  const [value, setValue] = useState('');
  return (
  	<input
     value={value}
		 onChange={e => {setValue(e.target.value)}}
    />  
  )
}

♠︎♠︎ 当编写一个组件时,你应该考虑哪些信息应该受控制(通过 props),哪些信息不应该受控制(通过 state)。

业务开发中,组件是受控或者非受控是明确的。但组件库中(如antd)有非常多的场景需要既支持受控模式又支持非受控模块(如input) <= 组件的状态既可以自己管理,也可以被外部控制。

推荐查看 ahooks useControllableValue[2](#2)

‼️区分:纯函数
  • 只负责自己的任务。它不会更改在该函数调用前就已存在的对象或变量。
  • 输入相同,则输出相同。给定相同的输入,纯函数应总是返回相同的结果。

不更改在该函数调用前就已存在的对象或变量 => 对于 props 同样至关重要!

将 props 视为只读

🧶 探讨:不要在 state 中镜像 props

父组件

javascript 复制代码
import {useState} from 'react';
import Message from './Message.tsx';

export default function Hello () {
    const [message, setMessage] = useState('world');
    return (
        <>
            <input type="text" value={message} onChange={(e) => setMessage(e.target.value)}/>
            <Message message={message}></Message>
        </>
    )
}

子组件

javascript 复制代码
import {useState} from 'react';

export default ({message}: {message: string}) => {
    const [msg, setMsg] = useState(message);
    return <div>hello {msg}</div>
}

‼️这里,一个 msg state 变量被初始化为 message 的 prop 值。这段代码的问题在于,如果父组件稍后传递不同的 message 值(例如,将其从 'world' 更改为 'ligang'),则 msg state 变量将不会更新! state 仅在第一次渲染期间初始化。

这就是为什么在 state 变量中,"镜像"一些 prop 属性会导致混淆的原因。相反,你要在代码中直接使用 message 属性。

💯 如果你想给它起一个更短的名称,请使用常量:

javascript 复制代码
export default ({message}: {message: string}) => {
    const msg = message;

这种写法就不会与从父组件传递的属性失去同步。

🔛只有当你 想要 忽略特定 props 属性的所有更新时,将 props "镜像"到 state 才有意义。

按照惯例,prop 名称以 initialdefault 开头,以阐明该 prop 的新值将被忽略:

javascript 复制代码
export default ({initialMessage}: {initialMessage: string}) => {
    // 这个 `message` state 变量用于保存 `initialMessage` 的 **初始值**。
  	// 对于 `initialMessage` 属性的进一步更改将被忽略。
  	const [msg, setMsg] = useState(initialMessage);

  1. https://react.docschina.org/reference/react/Children#alternatives Children替代方案 ↩︎

  2. https://ahooks.js.org/zh-CN/hooks/use-controllable-value#usecontrollablevalue usecontrollablevalue ↩︎

相关推荐
张元清15 小时前
React useDropZone Hook:搭建一个文件拖放区(2026)
javascript·react.js
无人生还16 小时前
从 Vue3 到 React · 快速上手系列第 5 篇:事件处理与表单(受控组件 vs v-model)
前端·vue.js·react.js
光影少年16 小时前
RN Bridge 原理
前端·react native·react.js
moMo17 小时前
用 React 写一个 TodoList
react native·react.js
To_OC1 天前
写了三遍 Todo List,我终于搞懂了 React 父子组件到底怎么通信
前端·javascript·react.js
kyriewen1 天前
别再乱用useEffect了——你写的10个里有8个不该存在
前端·javascript·react.js
zandy10111 天前
衡石 Agentic BI的ReAct 推理框架在 Agentic BI 中的工程化实践
前端·javascript·react.js
朝阳391 天前
react19【系列实用教程】JS 项目升级为 typescript
javascript·react.js·typescript
labixiong1 天前
React Compiler 用 Rust 重写了,编译提速 10 倍——手写 useMemo 的日子到头了
react.js·rust
张元清2 天前
React useDeepCompareEffect:修复 useEffect 的对象依赖问题(2026)
javascript·react.js