React笔记_组件之间进行数据传递 - 教程
目录
父子组件传值- props
在React中父子组件传值是单向数据流 => 数据必须是由父级传到子级或者子级传递给父级层层传递!
父传子
父组件通过在子组件的JSX标签上添加属性的方式来传递数据,子组件通过 props 对象接收。
传递的数据类型是不受限制的 = > 可以是字符串、数字、数组、对象、函数、甚至JSX元素。
父组件
<son 子组件接收的属姓名=父组件的属性值></son>import {useState } from 'react' import Funcom from '../component/Funcom' import Clcom from '../component/Clcom' export default function Page1(){ const [num, setNum] = useState(1) return ( <div> { /* 函数子组件 */ } <Funcom num={num }/> { /* 类子组件 */ } <Clcom num ={num }/> <button onClick={ ()=> { setNum(preNum=>preNum+1) } }>editNum< /button> < /div> ) }子组件:
- 函数子组件组件:在调用函数时将props作为参数传入;
function FunSon(props){ // props直接使用 }export default function Fun(props){ console.log('渲染了') // 无论有没有接收参数只要父组件更新都会重新渲染子组件 return ( <div> <h4>函数子组件==》{props.num }< /h4> < /div> ) } - 类子组件:通过this获取props
class ClaSon extends React.Component{ // this.props使用 }import React from 'react' export default class Clcom extends React.Component { render() { console.log('render') // 无论有没有接收参数只要父组件更新都会重新渲染子组件 return ( < > <h4>类组件==》{ this.props.num }< /h4> < /> ) } }
- 函数子组件组件:在调用函数时将props作为参数传入;
子传父
子组件不能直接修改父组件的状态(数据单向流动),果需要,父组件必须传递一个函数给子组件作为 prop,子组件在需要时调用这个函数,将数据作为参数传回给父组件。
- 父组件
<Son 子组件调用的方法名={父组件的方法}></Son> - 子组件
// 当子组件想要修改父组件的数据时 // val是要修改的值 props.方法名(val) // 函数组件 this. props.方法名(val) // 类组件 - 举例说明
父组件
函数子组件import {useState } from 'react' import Funcom from '../component/Funcom' import Clcom from '../component/Clcom' export default function Page1(){ const [num, setNum] = useState(1) function editNum(val){ setNum(val) } return ( <div> { /* 函数子组件 */ } <Funcom num={num } editNum={editNum }/> { /* 类子组件 */ } <Clcom num ={num } editNum={editNum }/> < /div> ) }
类子组件export default function Fun(props){ return ( <div> <h4>函数子组件==》{props.num }< /h4> <button onClick={ ()=> {props.editNum(props.num+2) } }>函数组件editNum< /button> < /div> ) }import React from 'react' export default class Clcom extends React.Component { render() { console.log('render') return ( < > <h4>类组件==》{ this.props.num }< /h4> <button onClick={ ()=> { this.props.editNum(this.props.num+1) } }>类组件editNum< /button> < /> ) } }
嵌套组件传值-Context API
概念
Context API 是 React 提供的一种组件间通信机制,允许数据在组件树中直接传递,无需通过 props 逐层传递。
React.createContext API
React.createContext 是一个函数,用于创建一个Context对象 => 该对象是管理 “全局”或“跨组件”数据的容器和通信机制。
React.createContext(defaultValue)
参数:defaultValue;
当一个组件在树中找不到匹配的 Provider 时,React.Consumer/useContext就会返回这个 defaultValue;
这个默认值对于测试组件或在没有提供 Provider 的情况下非常有用
返回值:一个Context对象
{ $$typeof: Symbol(react.context), // React 内部用于识别类型的符号 _currentValue: 'light', // 内部保存的当前值 Provider: { ... }, // Provider 组件 Consumer: { ... }, // Consumer 组件 (已较少使用) displayName: undefined, // 用于 React DevTools 显示的名称 }
Provider组件
Provider组件是React.createContext函数返回对象的属性,允许消费组件订阅 Context 的变化。
<MyContext.Provider value={...}>
<!-- 子组件树-->
</MyContext.Provider>
value就是要传递给所有下层组件的数据,只要 value发生变化,所有订阅该 Context 的后代组件都会强制重新渲染,即使它们使用了 React.memo 或 shouldComponentUpdate。
正确示例
const ThemContext = createContext({theme:'right', color: 'red'
})
const [theme, setTheme] = useState({theme:'right', color: 'red'
})
return (
<div>
<ThemContext.Provider value={theme
}>
{
/* 其中所有的子组件以及其子组件都可以获取到value */
}
<Funcom />
<Clcom />
<
/ThemContext.Provider>
<
/div>
)
错误示例
<div>
<ThemContext.Provider value={{theme:'right', color: 'red'}}>
{/* 其中所有的子组件以及其子组件都可以获取到value */}
<Funcom />
<Clcom />
</ThemContext.Provider>
</div>
每次渲染时,value={ theme:‘right’, color: ‘red’ }都会创建一个全新的对象,导致所有消费者不必要的重渲染。
消费 Context
kan su me
React.Consumer组件
React.Consumer是类组件中订阅 Context 变更的方式,函数组件已经逐渐使用useContext这个hook来替代了。
其子元素是一个函数,函数的参数就是 ThemeContext 的当前值,返回值就是需要渲染的vodm;
<ThemeContext.Consumer>
{value=>{
vdom
}
}
</ThemeContext.Consumer>
举例说明
将context提取为一个单独的文件themeContext
import {createContext } from 'react' export default createContext({theme:'right', color: 'red' })在顶级组件引入
import {useState } from 'react' import Funcom from '../component/Funcom' import Clcom from '../component/Clcom' import ThemContext from '../utils/themeContext' export default function Page1(){ const [theme, setTheme] = useState({theme:'right', color: 'red' }) function editTheme(){ setTheme(prevalue => ({ ...prevalue, theme: prevalue.theme=='right' ? 'dack' : 'right', })) } return ( <div> <ThemContext.Provider value={theme }> { /* 其中所有的子组件以及其子组件都可以获取到value */ } <Funcom /> <Clcom /> <button onClick={editTheme }>edittheme< /button> < /ThemContext.Provider> < /div> ) }子组件中若是不需要使用则完全不需要改变
在想要使用的组件去消费,比如此处在孙组件使用
import React from 'react' import ThemeContext from '../utils/themeContext' class SonFun2 extends React.Component{ render(){ console.log('孙组件') return( <ThemeContext.Consumer> { value=> ( < > <h4>今天的主题是:{value.theme }< /h4> <div>今天的颜色是:{value.color }< /div> < /> ) }< /ThemeContext.Consumer> ) } }当在顶级组件点击按钮修改value值时会重新渲染所有组件,包括子组件(因为通过setState去修改数据本身就会渲染所有子组件)
useContext Hook
useContext是函数组件中订阅 Context 变更的方式
const value = useContext(ThemeContext)
value就是要传递给所有下层组件的数据,只要 value发生变化,所有订阅该 Context 的后代组件都会强制重新渲染。
举例说明
function SonFun(){
const value = useContext(ThemeContext)
return (
<div>
<h4>
function<
/h4>
<h4>今天的主题是:{value.theme
}<
/h4>
<div>今天的颜色是:{value.color
}<
/div>
<
/div>
)
}
区别
| 函数组件 | 类组件 | |
|---|---|---|
| 方式 | useContext API | Context.consumer组件 |
| 语法 | 只需要在函数顶部调用hook ,简单明了 | 需要在组件jsx语法中嵌套一个函数,语法稍显冗长 |
| 易读性 | 可以并行调用多个context,简单易懂 | 若是存在多个context,容易造成回调地狱 |
| 性能 | 基本相同 | 基本相同 |
使用场景
推荐在值不经常改变的地方使用context,如主题切换、用户信息认证、管理一些全局的、许多组件都需要的数据;
对于频繁更新的数据, 如表单输入、实时坐标等,Context 可能不是最优解,因为只要 Context 的 value 变化,所有消费该 Context 的组件都会重新渲染,即使它们只使用了 value 的一部分。
浙公网安备 33010602011771号