其实组件之间的传参思路基本都差不多,我们今天来学下react组件之间的传参。
众所周知 ,在业务开发中,无论用的什么框架,首要熟悉的有以下几点:
-
项目搭建,基础配置,命名规范。
-
路由配置,配置路由规则等。
-
组件通信,组件规范等等。
我们今天要探究的就是React中组件通信的几种方式,以及各自的应用场景。
{#_label1}
父子组件通信 {#heading-1}
在React中,父组件可以通过 props 向子组件传递数据和回调函数,从而实现父子组件之间的通信。同时,子组件可以通过调用父组件传递的回调函数来向父组件传递数据或者触发父组件的行为,有以下几个注意要点。
-
props传参,传入数据是只读的。
-
函数式组件可以直接解构用,类组件需要通过this.props.xxxx。
-
子组件数据传父组件时,回调函数的返回值就是传的参。
// ParentComponent.js
import React, { useState } from 'react';
import ChildComponent from './ChildComponent';
function ParentComponent() {
const [messageFromChild, setMessageFromChild] = useState('');
const handleMessageFromChild = (message) => {
setMessageFromChild(message);
};
return (
<div>
<h1>Parent Component</h1>
<p>Message from Child: {messageFromChild}</p>
<ChildComponent giveChildren={parentData} onMessage={handleMessageFromChild} />
</div>
);
}
export default ParentComponent;
// ChildComponent.js
//1.函数式组件
import React from 'react';
function ChildComponent(props) {
const { onMessage , parentData } = props;
const sendMessageToParent = () => {
onMessage('Hello from Child!');
};
return (
<div>
<h2>Child Component</h2>
<h2>{ parentData }</h2>
<button onClick={sendMessageToParent}>Send Message to Parent</button>
</div>
);
}
export default ChildComponent;
//1. 类组件
import React, { Component } from 'react'
export default class ChildComponent extends Component {
render() {
return (
<div>
{this.props.parentToChild}
</div>
)
}
}
小结:我们看上面代码,通过在组件上属性名,在子组件中,就可以从props中解构出该属性,这个属性也可以是一个回调函数,当该回调函数调用时,入参就会在父组件的形参那里拿到,跟jsonp的原理一样。
{#_label2}
父孙组件通信 {#heading-2}
聪明的同学相信可以通过父子组件通信举一反三,但是为了一个传参,写好几层回调,这种代码看起来就不适用,所以为了解决这个问题,react 给我们提供了一个方法 createContext 这是一个创建React 上下文的函数,这个上下文提供了组件中共享值的方法,不用显示的通过props层层传递。
//跨组件通信
import React, { Component } from 'react'
//创建context 给初始值
const UserMessage = React.createContext({
nickName: 'yyy',
level: 1
})
export default class TextSingal extends Component {
constructor(props) {
super(props)
this.state = {
nickName: 'kkk',
level: 99,
name: 'ppp',
age: 9999
}
}
render() {
const { name, age } = this.state
return (
<div>
<h2>爷爷组件</h2>
<h3>name:{name}</h3>
<h3>age:{age}</h3>
{/* 改变数据孙组件也更新 */}
<button onClick={() => this.handelClick()}>updated</button>
{/* 传入state对象和foo回调函数 */}
{/* foo函数用于孙组件和爷组件通信 */}
<UserMessage.Provider value={{ ...this.state, foo: (name, age) => this.updateDatas(name, age) }}>
<Father />
</UserMessage.Provider>
</div>
)
}
handelClick() {
this.setState({
nickName: '虎威神',
level: 9999
})
}
updateDatas(name, age) {
this.setState({
name,
age
})
}
}
class Father extends Component {
render() {
return (
<div>
<h2>爸爸组件</h2>
<Son />
</div>
)
}
}
class Son extends Component {
render() {
// 解构
const { nickName, level, foo } = this.context
return (
<div>
<h2>儿子组件</h2>
<h3>nickname:{nickName}</h3>
<h3>level:{level}</h3>
{/* 下面两种调用方式都可以 */}
{/* 改变爷组件的数据 */}
<button onClick={() => this.handelClick()}>updated</button>
<button onClick={() => foo('牛霸天', 18)}>updated</button>
</div>
)
}
handelClick() {
this.context.foo('牛霸天', 18)
}
}
// 接受爷组件传递的值
Son.contextType = UserMessage
小结:通过上述我们创建了一个context,然后用context.provider 将组件包裹,那么被包裹的组件将会共享这个context,在context上定义回调,在孙组件通过 this.context 即可调用回调,或者使用传入数据。
{#_label3}
兄弟组件通信 {#heading-3}
相对于Vue中兄弟组件传参,react会相对原始一些,Vue中可以通过evenbus,便捷的在各种组件中传递参数。而react的做法是,在兄弟组件共同的父组件中,创建一个公用的state,然后兄弟A组件通过跟父组件传递传参改变这个state,父组件将新值也传给B组件,以达到兄弟组件传参的目的。
{#_lab2_3_0}
父组件 {#heading-4}
//父组件
import React, {Component} from "react"
import Abrother from './Abrother'
import Bbrother from './Bbrother'
export default class common extends Component {
// 公共的组件部分
state = {
inputValue:''
}
handleUpdate = (inputValue) => {
this.setState({
inputValue
})
}
render(){
return(
<>
<Abrother sendFn={this.handleUpdate}/>
<Bbrother sendValue={this.state.inputValue}/>
</>
)
}
}
兄弟A {#heading-5}
import React,{Component} from "react";
export default class Abrother extends Component {
// 兄弟组件A需要将值先传给一个公共的父组件
state = {
inputValue:''
}
handleChange = (e)=>{
console.log(e.target.value);
this.setState({
inputValue:e.target.value
})
}
handleSend = () => {
const {sendFn} = this.props;
sendFn(this.state.inputValue)
}
render(){
return(
<>
<div>
<span>A组件</span>
<input type='text' value={this.state.inputValue} onChange={this.handleChange}></input>
<button onClick={this.handleSend}>发送A组件的值</button>
</div>
</>
)
}
}
兄弟B {#heading-6}
import React, {Component} from "react"
export default class Bbrother extends Component {
render(){
const { sendValue} = this.props;
return (
<div>
<span>b组件</span>
<h1>{ sendValue }</h1>
</div>
)
}
}
小结: 组件A,想要将输入框中的值传给组件B,那么先在父组件的 state 中定义一个变量,这个变量就是要传给组件 B 中的值,父组件中将这个值通过props的形式传入b组件。接下来定义父组件和A组件中的回调函数触发,当A组件数据移动,调用回调函数,改变父组件 state 中的值,以达到将新值传给B组件的目的。
{#_label4}
跨组件通信 {#heading-7}
props ,当组件层级连贯且浅的时候,可以直接使用props进行通信。
context API , 当组件数据跨越了层级的时候,可以用此方法省去层层props。
事件总线,evenbus等。通过引入库或者自己手写一个简单的,进行通信。
使用 Redux MobX,对于非常复杂的组件中共享状态的数据处理时,可以用这两个库进行处理
使用 Refs,直接操作DOM 元素,或者组件实例。