Vue-2组件通信

132 阅读3分钟

react2 - 组件通信

  1. 父传子

    父传子:
        1. 在父组件使用子组件的地方,定义属性传参
        2. 子组件中通过props接收参数,类组件需要this.props.属性名,函数组件.props.属性名
        传参类型:
            1. 字符串...  基本数据类型    
            2. 对象 {}
            3. 函数 ()=>{}
            4. jsx
    
    export default class Parent1 extends Component {
        state = {
            message: '这是Parent1父组件内容',
            user: {
                name: 'jack',
                age: 18,
            },
        }
        render() {
            return (
                <div className="container">
                    <h2>父传子 Parent1组件</h2>
                    <Son
                        msg={this.state.message}
                        user={this.state.user}
                        callback={this.getMessage}
                        jsxdemo={
                            <div>
                                <p>jsx作为参数{this.state.message}</p>
                                <p>价格:188.98</p>
                            </div>
                        }
                    />
                    <SonF msg={this.state.message} user={this.state.user} jsxdemo={<h2>这是jsx传参,类似vue中插槽</h2>} />
                </div>
            )
        }
        getMessage = () => {
            console.log('这是传的函数参数')
        }
    }
    
    // 类子组件
    export default class Son extends Component {
        render() {
            return (
                <div className="son-a">
                    <h2>Son组件</h2>
                    <p>{this.props.msg}</p>
                    <p>{this.props.user.name}</p>
                    { this.props.jsxdemo }
                    <button onClick={this.bindGetMessage}>确定</button>
                </div>
            )
        }
    ​
        bindGetMessage = () => {
            let messg = this.props.callback
            messg()
        }
    }
    // 函数子组件
    export default function SonF(props) {
      return (
        <div className='son-f'>
            <h2>函数组件SonF</h2>
            <p>{props.msg}</p>
            <p>{props.user.age}</p>
            {/* 插槽位置 */}
            { props.jsxdemo }
        </div>
      )
    }
    ​
    
  2. 子传父

    export default class Parent extends Component {
      state={
        content:''
      }
      render() {
        return (
          <div style={ {width:'400px',height:'400px',backgroundColor:'pink'} }>
              <h2>子传父 - 父组件Parent</h2>
              {/* 2. 带参的函数传给子组件 */}
              <Son2 emitMsg={ (msg)=>{this.getMessage(msg)} } />
              {this.state.content}
          </div>
        )
      }
      /**
       * 1. 定义一个带参的函数
       * @param {*} msg 接收子组件实参
       */
      getMessage = (msg)=>{
         console.log('msg ',msg);
         this.setState({content:msg})
      }
    }
    ​
    
    export default class Son2 extends Component {
        state = {
            content: '这是子组件内容',
        }
        render() {
            return (
                <div style={ {width:'200px',height:'100px',backgroundColor:'skyblue'}}>
                    <h2>Son2子组件</h2>
                    <button onClick={this.bindSendMessage}>子传父</button>
                </div>
            )
        }
        /**
         * 3. 点击按钮发送数据给父组件
         */
        bindSendMessage = () => {
            this.props.emitMsg(this.state.content) //在子组件中 调用父组件传递的函数参数
        }
    }
    ​
    
  3. 兄弟组件通信

    兄弟组件之间传递数据,可以将Son组件的数据传递给自己的父组件,父组件将数据传递给Son2组件。备注:父组件是 son 和 son2 的父亲。

    /**
     * 兄弟组件通讯
     *   SonA组件内容发送给SonB组件显示
     */
    export default class SonA extends Component {
      state = {
          content:'这是SonA组件发送给SonB组件的内容'
      }
      render() {
        return (
          <div style={ {width:'200px',height:'200px',backgroundColor:'skyblue'}}>
              <h2>SonA子组件</h2>
              <button onClick={()=>{ this.props.emitMsg(this.state.content) }  }>发送信息</button>
          </div>
        )
      }
    ​
    }
    
    export default function SonB(props) {
      return (
        <div style={ {width:'200px',height:'100px',backgroundColor:'pink'}}>
            <h2>SonB 组件</h2>
            <p>{props.sendMsg}</p>
        </div>
      )
    }
    // 解构参数
    // export default function SonB({sendMsg}) {
    //     return (
    //       <div style={ {width:'200px',height:'100px',backgroundColor:'pink'}}>
    //           <h2>SonB 组件</h2>
    //           <p>{sendMsg}</p>
    //       </div>
    //     )
    //   }
      
    
  4. 提供者与消费者

    • React.createContext
    • Provider
    • Consumer
    • 提供者与消费者可以用来实现组件的跨级通信,提供者 provider 提供数据,消费者 consumer 使用数据。需要注意的是 provider 有一个固定的属性 valueconsumer 需要使用函数然后返回jsx的形式,这样设计便于传参。
    // contextbus 对比于vue中的事件总线bus
    import React from "react"
    export const {Provider,Consumer} = React.createContext()
    
    // 提供者 Provider 提供数据的组件
    import { Provider } from './demo3/contextbus'
    
    export default class App extends Component {
    	state = {
    		message: '兄弟组件通讯-初始值',
    		msg: '跨组件通讯-app组件内容',
    	}
    	render() {
    		return (
    			<Provider value={this.state.msg}>
    				<div className="container">
    					<h1>App 父组件</h1>
    					{/* 父传子示例 <Parent1 />*/}
    					{/* 子传父示例 <Parent /> 
    
    					{/* 兄弟通讯示例 */}
    					{/* <SonA emitMsg={ (msg)=>{this.getMessage(msg)} }/> */}
    					{/* <SonB sendMsg={this.state.message}/> */}
    
    					{/* 跨组件通讯示例 */}
    					{/* <ComA /> */}
    					
    					<RefDemo/>
    				</div>
    			</Provider>
    		)
    	}
    
    	/**
    	 * 带参的函数
    	 * @param {*} msg
    	 */
    	getMessage = msg => {
    		this.setState({ message: msg })
    	}
    }
    
    // 消费者 Consumer 获得、使用数据的组件 可多个
    export default class ComB extends Component {
      render() {
        return (
            <div style={ {width:'100px',height:'100px',backgroundColor:'blue'}}>
            <h2>ComB</h2>
            <ComC/>
            <Consumer>
              { value => <h2>{value}</h2>}
            </Consumer>
        </div>
        )
      }
    }
    
  5. refs

    • Refs提供了一种方式,允许我们访问DOM节点或在render方法中创建React元素

    • 使用React.createRef()创建的,并通过ref属性附加到React元素

    • ref属性:

      • 当ref属性用于html元素时,构造函数中使用React.createRef()创建的ref接收底层DOM元素作为其current属性
      • 当ref属性用于自定义class组件时,ref对象接收组件的挂载实例作为其current属性
      语法:
      1、使用React.createRef()创建的ref
      	例:this.bindNum = React.createRef()
      
      2、在需传参的组件中使用ref属性
      	例: <Text2 ref={this.bindNum}/>
              
      3、使用current属性获取DOM节点或组件
      	例:this.bindNum.current
      
    export default class RefDemo extends Component {
    	constructor() {
    		super()
            this.pRef = React.createRef()
            this.counterRef = React.createRef()
    	}
        state = {
            content:''
        }
    	render() {
    		return (
    			<div>
    				<h2>refs操作dom(react元素或子组件)</h2>
                    <h2>{this.state.content}</h2>
    				<p id="p1" ref={this.pRef}>操作React元素</p>
                    <Counter ref={this.counterRef}/>
    				<button onClick={this.bindUpdateContent}>更新内容</button>
    			</div>
    		)
    	}
    
    	bindUpdateContent = () => {
            //原生js操作元素内容
    		// const pEle = document.getElementById('p1')
    		// pEle.innerHTML = '新的内容'
            // const pEle = this.pRef.current
            // console.log(pEle);
            // pEle.innerHTML = '通过ref更改新的内容'
    
            const CounterEle = this.counterRef.current
            console.log('CounterEle ',CounterEle);
            console.log('CounterEle.state.num ',CounterEle.state.num);
    
            this.setState({content:CounterEle.state.num})
    	}
    }
    
    export default class Counter extends Component {
    	state = {
    		num: 10,
    	}
    	render() {
    		return (
    			<div style={ {width:'200px',height:'200px',backgroundColor:'skyblue'}}>
    				<h2>Counter组件</h2>
                    <p>{this.state.num}</p>
    			</div>
    		)
    	}
    }
    

    \