react中组件之间的通信

本文详细介绍了React中组件之间的传值方式,包括父传子、子传父以及任意组件间的通信。通过消息订阅-发布机制(pubsub-js)实现组件间通信,并探讨了Context在祖孙组件间通信的应用。此外,还提供了一个todoList案例来实践这些概念。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

  通过 react实现todoList案例总结父子组件之间传值的问题。

  口诀:属性向下流,事件向上走

1、父传子

父组件传值给子组件

class App extends Component {
    state = {todos: [{id: 1, name: '吃饭', done: true},{id: 2, name: '睡觉', done: true} ]}
    render() {
        return (
            <div className="todo-container">
                    <List todos={this.state.todos}/>{/*传值给子组件*/}
            </div>
        );
    }
}

子组件接收父组件传递的数据

export default class List extends Component {
    render() {
        //接收父组件传递过来的参数
        const {todos}=this.props
        console.log(todos);
        return (
            <div>
            </div>
        )
    }
}

在这里插入图片描述

2、子传父

父组件向子组件传递一个函数

class App extends Component {
    state = {
        todos: [
            {id: 1, name: '吃饭', done: true},
            {id: 2, name: '睡觉', done: true},
            {id: 3, name: '码代码', done: false}
        ]
    }
    //用于添加一个todo,接收的参数是todo对象
    addTodo = (todoObj) => {
        //获取原来的todos
        const {todos} = this.state
        //    追加一个todos
        const newTodos = [todoObj, ...todos];
        //    更新状态
        this.setState({
            todos: newTodos
        })
    }

    render() {
        return (
            <div className="todo-container">
                <div className="todo-wrap">
                    <Header onAddTodo={this.addTodo}/>{/*向子组件传递一个函数,一般会在前面+on*/}
                    <Footer/>
                </div>
            </div>
        );
    }
}

子组件调用父组件传递过来的函数

export default class Header extends Component {
    //鼠标按下时添加任务
    handleKeyUp = (e) => {
        const {value} = e.target
        if (e.keyCode !== 13) return
        console.log(value);
        //准备好一个todo对象
        const todoObj = {id: nanoid(), name: value, done: false};
        //    执行父组件传过来的函数
        this.props.onAddTodo(todoObj)
    }

    render() {
        return (
            <div className="todo-header">
                <input onKeyUp={this.handleKeyUp} type="text" placeholder="请输入你的任务名称,按回车键确认"/>
            </div>
        )
    }
}

3、任意组件间的通信

3.1、消息订阅-发布机制(pubsub-js)

①、下载
  npm install pubsub-js --save

②、使用

1)	import PubSub from 'pubsub-js' //引入

2)	PubSub.subscribe('delete', function(msg,data){ }); //订阅

3)	PubSub.publish('delete', data) //发布消息

组件将要卸载的时候需要取消订阅

Search.js

  发布


import React, {Component} from 'react';
import PubSub from "pubsub-js";
import axios from "axios";

export default class Search extends Component {
    search = () => {
        //    获取用户的输入(连续解构赋值+重命名)
        const {keyWordElement: {value: keyWord}} = this
        //  1、发布消息
        console.log('search组件发布消息了');
        //发送请求前通知list更新状态
        PubSub.publish('atGuiGu', {isFirst: false, isLoading: true})
        //    发送网路请求
        axios.get(`/api1/search/users?q=${keyWord}`).then(res => {
            console.log('对', res);
            //请求成功后通知list更新状态
            PubSub.publish('atGuiGu', {isLoading: false, users: res.data.items})
        }, err => {
            console.log('错啦', err);
            PubSub.publish('atGuiGu', {isLoading: false, err: err.message})
        })
    }

    render() {
        return (
            <div>
                <section className="jumbotron">
                    <h3 className="jumbotron-heading">搜索github用户</h3>
                    <div>
                        <input ref={c => this.keyWordElement = c} type="text" placeholder="输入关键词点击搜索"/>&nbsp;
                        <button onClick={this.search}>搜索</button>
                    </div>
                </section>
            </div>
        )
    }
}

List.js

  订阅

import React, {Component} from 'react';
import "./index.css"
import PubSub from "pubsub-js";

export default class List extends Component {
    state = {
        users: [],
        isFirst: true,//是否为第一次打开页面
        isLoading: false,//是否加载中
        err: ''//存储请求相关的错误信息
    }

    //2、list订阅消息
    componentDidMount() {
        this.message = PubSub.subscribe('atGuiGu', (msg, objState) => {
            console.log("list组件收到数据了", objState);
            this.setState(objState)
        })
    }

    componentWillUnmount() {
    //3、组件将要卸载的时候取消订阅
        PubSub.unsubscribe(this.message)
    }

    render() {
        const {users, err, isFirst, isLoading} = this.state
        return (
            <div>
                <div className="row">
                    {
                        isFirst ? <h2>欢迎使用,输入关键字,随后点击搜索</h2> :
                            isLoading ? <h2>loading....</h2> :
                                err ? <h2 style={{color: "red"}}>{err}</h2> :
                                    users.map((item) => {
                                        return (
                                            <div className="card" key={item.id}>
                                                <a rel="noreferrer" href={item.html_url} target="_blank">
                                                    <img alt="head_portrait"
                                                         src={item.avatar_url}
                                                         style={{width: "100px"}}/>
                                                </a>
                                                <p className="card-text">{item.login}</p>
                                            </div>
                                        )
                                    })
                    }
                </div>
            </div>
        )
    }
}

4、context

  一种组件间通信方式, 常用于【祖组件】与【后代组件】间通信。

  在应用开发中一般不用context, 一般都用它的封装react插件

  1. 创建Context容器对象:
const XxxContext = React.createContext()  
  1. 渲染子组时,外面包裹xxxContext.Provider, 通过value属性给后代组件传递数据:
<xxxContext.Provider value={数据}>
		子组件
</xxxContext.Provider>

案例代码:

import React, {Component} from 'react';

// 1) 创建Context容器对象:
const MyContext = React.createContext();

class A extends Component {
    state = {name: "Bob", age: 18}
    render() {
        const {name, age} = this.state
        return (
            <div style={{backgroundColor: "green", padding: "10px"}}>
                <h1>我是A组件grandfather</h1>
                <h1>我的用户名是:{name}</h1>
                {/*渲染子组时,外面包裹xxxContext.Provider, 通过value属性给后代组件传递数据:*/}
                <MyContext.Provider value={{name: name, age: age}}>
                    <B/>
                </MyContext.Provider>
            </div>
        )
    }
}

export default A;

  1. 后代组件读取数据:

  第一种方式:仅适用于类组件

//第一种方式:仅适用于类组件 
	  static contextType = xxxContext  // 声明接收context
	  this.context // 读取context中的value数据

案例代码:

class C extends Component {
    static  contextType = MyContext;
    render() {
        return (
            <div style={{backgroundColor: "yellow", padding: "30px"}}>
                <h5>我是C组件son</h5>
                <h5>我是A组件组件接收到的值,我的名字是:{this.context.name}</h5>
                <h5>我是A组件组件接收到的值,我的年龄是:{this.context.age}</h5>
            </div>
        );
    }
}

  第二种方式: 函数组件与类组件都可以

//第二种方式: 函数组件与类组件都可以
	  <xxxContext.Consumer>
	    {
	      value => ( // value就是context中的value数据
	        要显示的内容
	      )
	    }
	  </xxxContext.Consumer>

案例代码:

function C() {
    return (
        <div style={{backgroundColor: "yellow", padding: "30px"}}>
            <h5>我是C组件son</h5>
            <MyContext.Consumer>
                {
                    (value) => {
                        return (
                            <>
                                <h5>我是A组件组件接收到的值,我的名字是:{value.name}</h5>
                                <h5>我是A组件组件接收到的值,我的年龄是:{value.age}</h5>
                            </>
                        )
                    }
                }
            </MyContext.Consumer>
        </div>
    )
}

完整代码:

import React, {Component} from 'react';

// 1) 创建Context容器对象:
const MyContext = React.createContext();

class A extends Component {
    state = {name: "Bob", age: 18}

    render() {
        const {name, age} = this.state
        return (
            <div style={{backgroundColor: "green", padding: "10px"}}>
                <h1>我是A组件grandfather</h1>
                <h1>我的用户名是:{name}</h1>
                {/*渲染子组时,外面包裹xxxContext.Provider, 通过value属性给后代组件传递数据:*/}
                <MyContext.Provider value={{name: name, age: age}}>
                    <B/>
                </MyContext.Provider>
            </div>
        )
    }
}

export default A;

function B() {
    return (
        <div style={{backgroundColor: "red", padding: "20px"}}>
            <h3>我是B组件father</h3>
            <h3>我不接受A组件的传值</h3>
            <C/>
        </div>
    )
}
//类组件
class C extends Component {
    static  contextType = MyContext;
    render() {
        return (
            <div style={{backgroundColor: "yellow", padding: "30px"}}>
                <h5>我是C组件son</h5>
                <h5>我是A组件组件接收到的值,我的名字是:{this.context.name}</h5>
                <h5>我是A组件组件接收到的值,我的年龄是:{this.context.age}</h5>
            </div>
        );
    }
}


/*函数式组件
function C() {
    return (
        <div style={{backgroundColor: "yellow", padding: "30px"}}>
            <h5>我是C组件son</h5>
            <MyContext.Consumer>
                {
                    (value) => {
                        return (
                            <>
                                <h5>我是A组件组件接收到的值,我的名字是:{value.name}</h5>
                                <h5>我是A组件组件接收到的值,我的年龄是:{value.age}</h5>
                            </>
                        )
                    }
                }
            </MyContext.Consumer>
        </div>
    )
}
*/

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值