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> ) } }
引用