003*:通信(父子通信,非父子通信)

目录

1:父子通信-回调函数

2:父子通信-ref

3:非父子通信-中间人模式

4:非父子通信-订阅者模式

5: 非父子通信-生产消费者模式

6:插槽

正文

1:父子传值-回调函数

/*
案例
登录界面
一个输入用户名,一个输入密码
一个登录按钮,一个取消按钮
*/

import React, { Component } from 'react'

export default class CallBackCommunationComponent extends Component {
    state = {
        name: "",
        password: ""
    }
    render() {
        return (
            <div>
                <TextField text="用户名" inputValue={this.state.name} changeAction={(content)=>{
                    console.log(content)
                    this.setState({
                        name: content
                    })
                }}></TextField>
                <TextField text="密码" inputValue={this.state.password} changeAction={(content)=>{
                    console.log(content)
                    this.setState({
                        password: content
                    })
                }}></TextField>
                <button onClick={()=>{
                    // 通过状态获取到输入框的值
                    console.log(this.state.name, this.state.password)
                }}>登录</button>
                <button onClick={()=>{
                    // 清空输入框
                    this.setState({
                        name: "",
                        password: ""
                    })
                }}>取消</button>
            </div>
        )
    }
}

class TextField extends Component {
    render() {
        return (
            <div>
                <label>{this.props.text}</label>
                <input type='text' onChange={(event)=>{
                    console.log(event)
                    // 回调函数
                    this.props.changeAction(event.currentTarget.value)
                }} value={this.props.inputValue}/>
            </div>
        )
    }
}

2:父子传值-ref

/*
案例
登录界面
一个输入用户名,一个输入密码
一个登录按钮,一个取消按钮
*/

import React, { Component } from 'react'

export default class RefCommunationComponent extends Component {
    nameRef = React.createRef()
    passwordRef = React.createRef()

    render() {
        return (
            <div>
                <TextField text="用户名" ref={this.nameRef}></TextField>
                <TextField text="密码" ref={this.passwordRef }></TextField>
                <button onClick={()=>{
                    // 通过状态获取到输入框的值
                    console.log(this.nameRef.current.state.value, this.passwordRef.current.state.value)
                }}>登录</button>
                <button onClick={()=>{
                    // 清空输入框
                    this.nameRef.current.clear()
                    this.passwordRef.current.clear()
                    setTimeout(() => {
                        console.log(this.nameRef.current.state.value, this.passwordRef.current.state.value)
                    }, 0.3);
                }} >取消</button>
            </div>
        )
    }
}

class TextField extends Component {
    state = {
        value: ""
    }

    clear() {
        this.setState({
            value: ""
        })
    }
    render() {
        return (
            <div>
                <label>{this.props.text}</label>
                <input type='text' onChange={(e)=>{
                    this.setState({
                        value: e.target.value 
                    })
                }} value={this.state.value}/>
            </div>
        )
    }
}

3:中间人状态

/*
非父子通信方法1:中间人模式
demo 案例:
一个电影列表,点击电影进入显示对应的详情页

案例分析:
1:axios 请求数据
2:map 映射循环渲染
3:一个 app 组件,一个 item 组件,一个 detail 组件。item 组件点击,detail 组件展示对应的详情。item 组件和 detail 组件通信
*/

import React, { Component } from 'react'
import axios from 'axios'

export default class FileItemDetailComponent extends Component {
    constructor(props) {
        super(props)

        this.state = {
            filemaList: [],
            detail: ""
        }
        axios.get('http://localhost:3000/cinema.json').then(res => {
            console.log(res.data)
            this.setState({
                filemaList: res.data.data.cinemas
            })
        })
    }
    render() {
        return (
            <div>
                <ul>
                    {
                        this.state.filemaList.map(item => {
                            return (
                                // 1:传递给父组件,父组件通过props传递给子组件
                                <FileItemComponent key={item.cinemaId} item={{ ...item }} childChangeHandle={(value) => {
                                    console.log(value)
                                    this.setState({
                                        detail: value
                                    })
                                }}></FileItemComponent>
                            )
                        })
                    }
                </ul>
                {/* 2:父组件通过props传递给子组件, 父组件起到中间人作用,在两个兄弟之前尽量调度 */}
                <FileDetailComponent detail={this.state.detail}></FileDetailComponent>
            </div>
        )
    }
}


class FileItemComponent extends Component {

    render() {
        var { cinemaId, name, address } = this.props.item
        return (
            <div>
                <li style={{ height: "80px" }} onClick={() => {
                    this.props.childChangeHandle(address)
                }}>
                    <span >{name}</span>
                </li>
            </div>
        )
    }
}

class FileDetailComponent extends Component {

    render() {
        return (
            <div>
                {
                    this.props.detail
                }
            </div>
        )
    }
}

4:订阅者模式

/*
非父子通信方法2:订阅者模式
demo 案例:
一个电影列表,点击电影进入显示对应的详情页

案例分析:
1:axios 请求数据
2:map 映射循环渲染
3:一个 app 组件,一个 item 组件,一个 detail 组件。item 组件点击,detail 组件展示对应的详情。item 组件和 detail 组件通信
*/

import React, { Component } from 'react'
import axios from 'axios'

export default class FileItemDetailComponent extends Component {
    constructor(props) {
        super(props)

        this.state = {
            filemaList: [],
        }
        axios.get('http://localhost:3000/cinema.json').then(res => {
            console.log(res.data)
            this.setState({
                filemaList: res.data.data.cinemas
            })
        })
    }
    render() {
        return (

            <div>
                <ul>
                    {
                        this.state.filemaList.map(item => {
                            return (
                                <FileItemComponent key={item.cinemaId} item={{ ...item }}></FileItemComponent>
                            )
                        })
                    }
                </ul>
                <FileDetailComponent></FileDetailComponent>
            </div>
        )
    }
}


class FileItemComponent extends Component {
    
    render() {
        var {cinemaId, name, address} = this.props.item
        return (
            <div>
                <li  style={{ height: "80px" }} onClick={() => {
                    console.log(address)
                    // 3:发布者模式
                    bus.publish(address)
                }}>
                    <span >{name}</span>
                </li>
            </div>
        )
    }
}

class FileDetailComponent extends Component {
    constructor(props) {
        super(props)
        this.state = {
            detail: ""
        }
        // 2:订阅者模式
        bus.subscribe((value)=>{
            this.setState({
                detail: value
            })
        })
    }
    render() {
        return (
            <div>
                <h5>{this.state.detail}</h5>
            </div>

        )
    }
}
/* 1:定一个一个调度中心*/
var bus = {
    list: [],
    // 订阅
    subscribe(callback) {
        this.list.push(callback)
    },

    // 发布
    publish(content) {
        this.list.forEach(callback => {
            callback && callback(content)
        })
    }
}

// // 订阅者模式
// bus.subscribe((content)=>{
//     console.log('订阅者1'+content)
// })

// bus.subscribe((content)=>{
//     console.log('订阅者2'+content)
// })

setTimeout(() => {
    bus.publish("大家好")
}, 0);

5:生产者消费者模式

/*
非父子通信方法3:官方提供
demo 案例:
一个电影列表,点击电影进入显示对应的详情页

案例分析:
1:axios 请求数据
2:map 映射循环渲染
3:一个 app 组件,一个 item 组件,一个 detail 组件。item 组件点击,detail 组件展示对应的详情。item 组件和 detail 组件通信
4:使用生产和消费者模式
*/

import React, { Component } from 'react'
import axios from 'axios'

// 1: 创建全局上下文对象
const GloablContext = React.createContext()

export default class FileItemDetailComponent extends Component {
    constructor(props) {
        super(props)

        this.state = {
            filemaList: [],
            detail: ""
        }
        axios.get('http://localhost:3000/cinema.json').then(res => {
            console.log(res.data)
            this.setState({
                filemaList: res.data.data.cinemas
            })
        })
    }
    render() {

        return (
            // 2:供应商包裹 div 组件,提供给消费者
            <GloablContext.Provider value={
                {
                    // 消费者通过 value 拿到数据
                    call: "打电话",
                    sms: "短信服务",
                    detail: this.state.detail,
                    // 5: 消费者消费数据,并修改数据,修改数据后,重新渲染组件,更新itemdetail 中的消费者数据
                    changeValue: (value) => {
                        this.setState({
                            detail: value
                        })
                    }
                }
            }>
                <div>
                    <ul>
                        {
                            this.state.filemaList.map(item => {
                                return (
                                    <FileItemComponent key={item.cinemaId} item={{ ...item }}></FileItemComponent>
                                )
                            })
                        }
                    </ul>
                    <FileDetailComponent></FileDetailComponent>
                </div>
            </GloablContext.Provider>
        )
    }
}


class FileItemComponent extends Component {
    render() {
        // 父传子,通过结构函数, 写一个回到函数(可以传递参数),里面 return 组件。
        var { name, address, cinemaId } = this.props.item
        return (
            // 3:消费者包裹组件,消费数据
            <GloablContext.Consumer>
                {
                    (value) => {
                        console.log(cinemaId)
                        return (
                            <div>
                                <li  style={{ height: "80px" }} onClick={() => {
                                    console.log(address)
                                    // 4: 消费者消费数据,并修改数据
                                    value.changeValue(address)
                                }}>
                                    <span>{name}</span>
                                </li>
                            </div>
                        )
                    }
                }
            </GloablContext.Consumer>

        )
    }
}

class FileDetailComponent extends Component {
    render() {
        // 父传子,通过结构函数
        return (
            <GloablContext.Consumer>
                {
                    (value) => {
                        console.log(value)
                        return (
                            <div>
                                {/* 6:消费者显示更新之后的数据 */}
                                <h5>{value.detail}</h5>
                            </div>
                        )
                    }
                }
            </GloablContext.Consumer>
        )
    }
}

6:插槽

/*
插槽:特殊的属性
    1. 作用:让组件的子节点,显示到组件内部的位置上
    2:为了复用
    3:一定程度减少父子通信
*/

import React, { Component } from 'react'

export default class SlotComponent extends Component {
    render() {
        return (
            <div>
                <NavItem>
                    <span> <button>左侧按钮</button></span>
                    <button>右侧按钮</button>
                </NavItem>
            </div>
        )
    }
}

class NavItem extends Component {
    render() {
        return (
            <div>
                {this.props.children[0]}
                <h3>插槽</h3>
                {this.props.children[1]}
            </div>
        )
    }
}

 

 

引用

posted on 2024-01-26 15:03  风zk  阅读(9)  评论(0编辑  收藏  举报

导航