React之组件通讯(props使用,父传子,子传父,兄弟组件通讯,跨组件通讯
一、组件通讯介绍
组件时独立且封闭的单元,默认情况下,只能使用组件自己的数据
在组件化过程中,通常会将一个完整的功能拆分成多个组件,以更好的完成整个应用的功能
而在这个过程中,多个组件之间不可避免的要共享某些数据
为了实现这些功能,就需要打破组件的独立封闭性,让其与外界沟通。这个过程就是组件通讯
组件中的状态是私有的,也就是说,组件的状态只能在组件内部使用,无法直接在组件外使用
二、props基本使用与注意点
2.1 props基本使用
使用场景: 组件接收外部数据
作用: 接收(其他组件)传递给当前组件的数据
传递: 给组件标签添加属性
接收: 函数组件通过props参数接收 类组件通过this.props
核心代码
import React from 'react'
import ReactDOM from 'react-dom/client'
//创建函数组件 直接通过props
const Hello = (props) => {
console.log('函数组件传递的值', props)
return <div>我是函数组件</div>
}
//创建类组件 通过this.props
class Hello1 extends React.Component {
render() {
console.log('类组件传递的值', this.props)
return <div>我是类组件</div>
}
}
const h1 = (
<h1>
{/* 函数组件传值 */}
<Hello name="张三" age={19}></Hello>
{/* 类组件传值 */}
<Hello1 name="李四" age={19}></Hello1>
</h1>
)
ReactDOM.createRoot(document.querySelector('#root')).render(h1)
2.2 注意点
props是只读对象,无法修改
单向数据流(自上而下)
表示: 父组件中的数据可以通过 props 传递给子组件,并且,当父组件中的数据更新时,子组件就会自动接收到最新的数据
类比:就像瀑布的水一样只能从上往下流动,并且,当上游的水变浑浊,下游的水也会受到影响
可以传递任意数据(数字 字符串 布尔类型 数组 对象 函数 jsx)
三、父传子
步骤
1.父组件提供要传递的state数据
2.给子组件标签添加属性,值为state中的数据
3.子组件中通过props接收父组件中传递的数据
核心代码
父组件
class Parent extends React.Component {
state = {
money: 10000
}
render() {
const { money } = this.state
return (
<div>
<h1>我是父组件:{money}</h1>
{/* 将数据传递给子组件 */}
<Child money={money} />
</div>
)
}
}
子组件
function Child(props) {
return (
<div>
{/* 接收父组件中传递过来的数据 */}
<h3>我是子组件 -- {props.money}</h3>
</div>
)
}
四、子传父
步骤
1.父组件提供一个回调函数(用于接收数据)
2.将该函数作为属性的值 传递给子组件
3.子组件通过props 调用回调函数
4.将子组件的数据作为参数传递给回调函数
核心代码
父组件
class Parent extends React.Component {
state = {
money: 10000
}
// 回调函数
buyPhone = price => {
this.setState({
money: this.state.money - price
})
}
render() {
const { money } = this.state
return (
<div>
<h1>我是父组件:{money}</h1>
{/* 传递给子组件 */}
<Child money={money} buyPhone={this.buyPhone} />
</div>
)
}
}
子组件
const Child = (props) => {
const handleClick = () => {
// 子组件调用父组件传递过来的回调函数
props.buyPhone(100)
}
return (
<div>
<h3>我是子组件 -- {props.money}</h3>
<button onClick={handleClick}>买手机</button>
</div>
)
}
五、兄弟组件
状态提升
将共享状态提升到最近的公共父组件中,由公共父组件管理这个状态
公共父组件职责
1.提供共享状态
2.提供操作共享状态的方法
要通讯的子组件只需通过 props 接收状态或操作状态的方法
状态提升前
状态提升后
核心代码
父组件
import React, { Component } from 'react'
import ReactDOM from 'react-dom'
// 导入两个子组件
import Jack from './Jack'
import Rose from './Rose'
// App 是父组件
class App extends Component {
// 1. 状态提升到父组件
state = {
msg: '',
}
changeMsg = msg => {
this.setState({
msg,
})
}
render() {
return (
<div>
<h1>我是App组件</h1>
{/* 兄弟组件 1 */}
<Jack say={this.changeMsg}></Jack>
{/* 兄弟组件 2 */}
<Rose msg={this.state.msg}></Rose>
</div>
)
}
}
// 渲染组件
ReactDOM.createRoot(document.querySelector('#root')).render(<App />)
子组件A 修改值
import React, { Component } from 'react'
export default class Jack extends Component {
say = () => {
// 修改数据
this.props.say('you jump i look')
}
render() {
return (
<div>
<h3>我是Jack组件</h3>
<button onClick={this.say}>说</button>
</div>
)
}
}
子组件B 接收修改的值
import React, { Component } from 'react'
export default class Rose extends Component {
render() {
return (
<div>
{/* 展示数据 */}
<h3>我是Rose组件-{this.props.msg}</h3>
</div>
)
}
}
六、跨组件通讯 Context
组件之间的层级关系,除了以上两种常见的情况外,还有一种不太常见的情况,那就是:远房亲戚关系(也就是两个组件之间间隔较远)
实现方式: 使用 Context 来实现跨组件传递数据
Context 上下文,可以理解一个范围,只要在这个范围内容,就可以直接跨组件传递数据
核心代码
// 0 导入创建 context 的函数
import { createContext } from 'react'
// 1 创建 Context 对象
// createContext 的返回值是一个 对象
// 对象中包含了两个组件,分别是: Provider 状态的提供者组件(提供状态) Consumer 状态的消费者组件(使用状态)
const { Provider, Consumer } = createContext()
// 2 使用 Provider 组件包裹整个应用,并通过 value 属性提供要共享的数据
<Provider value="blue">
<div className="App">
<Node />
</div>
</Provider>
// 3 使用 Consumer 组件接收要共享的数据
<Consumer>
{color => <span>data参数表示接收到的数据 -- {color}</span>}
</Consumer>