探讨:围绕 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^ 而不是使用 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^

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

不更改在该函数调用前就已存在的对象或变量 => 对于 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 ↩︎

相关推荐
沉默璇年9 小时前
react中useMemo的使用场景
前端·react.js·前端框架
红绿鲤鱼10 小时前
React-自定义Hook与逻辑共享
前端·react.js·前端框架
loey_ln12 小时前
FIber + webWorker
javascript·react.js
zhenryx13 小时前
前端-react(class组件和Hooks)
前端·react.js·前端框架
老码沉思录17 小时前
React Native 全栈开发实战班 - 性能与调试之打包与发布
javascript·react native·react.js
沉默璇年1 天前
react中Fragment的使用场景
前端·react.js·前端框架
GISer_Jing1 天前
React渲染流程与更新diff算法
前端·javascript·react.js
老码沉思录1 天前
React Native 全栈开发实战班 - 性能与调试之内存管理
javascript·react native·react.js
yqcoder1 天前
reactflow 中 reactflowprovider 组件作用
前端·javascript·react.js
前端郭德纲1 天前
ReactNative的环境搭建
javascript·react native·react.js