1.props和方法

一、父组件向子组件传值

父组件通过属性的方式传递参数,子组件通过props来接收父组件传递过来的参数

React中是单向数据流,数据只能从父组件通过属性的方式传给其子组件,如下图:
在这里插入图片描述
在引用子组件的时候传递,相当于一个属性,例如:在子组件内通过porps.param获取到这个param的值。

父组件向子组件传值,通过props,将父组件的state传递给了子组件。
父组件(直接定义一个属性传值即可):

import React, { Component } from 'react'
import NavigationBar from './NavigationBar'

export class App extends Component {
  render() {
    return (
      <div>
        <NavigationBar title="我是父组件向子组件传的值" />
      </div>
    )
  }
}

export default App

子组件(通过this.props.父组件定义的属性 来接收父组件传递过来的参数):

import React from "react";

class NavigationBar extends React.Component{
    constructor(props){
        super(props);
        this.state = {
            title:''
        }
    }

    render(){
        return(
            <div>
                {this.state.title}
            </div> 
        )
    }
    componentDidMount(){
        this.setState({
            title:this.props.title
        })
    }
}

export default NavigationBar;

效果:
在这里插入图片描述

二、子组件向父组件传值

子组件通过调用父组件传递到子组件的方法向父组件传递消息的

在这里插入图片描述
子组件(通过this.props.事件名(参数)的方式向父组件传递参数):

import React from "react";

class NavigationBar extends React.Component{
    constructor(props){
        super(props);
        this.state = {
            title:''
        }
    }

    render(){
        return(
            <div>
                {this.state.title}
                <button onClick={()=>{
                    this.props.titleMessage("我是子组件向父组件传的值")
                }}>点击</button>
            </div> 
        )
    }
    componentDidMount(){
        this.setState({
            title:this.props.title
        })
    }
}

export default NavigationBar;

 

父组件:

import React, { Component } from 'react'
import NavigationBar from './NavigationBar'

export class App extends Component {
  constructor(props){
    super(props);
    this.state={
      titleMassage:''
    }
  }
  message=(titleMessage)=>{
        console.log(titleMessage);
        this.setState({
          titleMassage:titleMessage
        })
      }
  render() {
    return (
      <div>
        {this.state.titleMassage}
        <NavigationBar title="我是父组件向子组件传的值" titleMessage={this.message} />
      </div>
    )
  }
}

export default App

效果:

点击后的效果:
在这里插入图片描述

2.Evnentbus

class EventBus {
  constructor() {
    this.events = this.events || new Object(); 
  }
}
//首先构造函数需要存储event事件,使用键值对存储
//然后我们需要发布事件,参数是事件的type和需要传递的参数
EventBus.prototype.emit = function(type, ...args) { 
    let e; 
    e = this.events[type];  
    // 查看这个type的event有多少个回调函数,如果有多个需要依次调用。
    if (Array.isArray(e)) {  
        for (let i = 0; i < e.length; i++) {   
            e[i].apply(this, args);    
          }  
   } else {
          e[0].apply(this, args);  
         }  
   };
 //然后我们需要写监听函数,参数是事件type和触发时需要执行的回调函数
 EventBus.prototype.addListener = function(type, fun) { 
       const e = this.events[type]; 

        if (!e) {   //如果从未注册过监听函数,则将函数放入数组存入对应的键名下
         this.events[type]= [fun];
        } else {  //如果注册过,则直接放入
           e.push(fun);
        }
  };
// 移除监听
EventBus.prototype.removeListener = function (type, fn) {
  const handler = this._events.get(type); // 获取对应事件名称的函数清单

  // 如果是函数,说明只被监听了一次
  if (handler && typeof handler === 'function') {
    this._events.delete(type, fn);
  } else {
    let postion;
    // 如果handler是数组,说明被监听多次要找到对应的函数
    for (let i = 0; i < handler.length; i++) {
      if (handler[i] === fn) {
        postion = i;
      } else {
        postion = -1;
      }
    }
    // 如果找到匹配的函数,从数组中清除
    if (postion !== -1) {
      // 找到数组对应的位置,直接清除此回调
      handler.splice(postion, 1);
      // 如果清除后只有一个函数,那么取消数组,以函数形式保存
      if (handler.length === 1) {
        this._events.set(type, handler[0]);
      }
    } else {
      return this;
    }
  }
};
  const eventBus = new EventBus();
  export default eventBus;

  

然后,我们在login组件中加入

EventBus.emit('login',values.userName)

在需要监听的组件加入

EventBus.addListener('login',(name)=>{
            this.setState({user:name})
        })
也可以利用node自己的EventEmitter。

解决步骤
1、直接引入并新建实例,不用额外npm install events --save
直接引入并新建实例
2、把第一步实例化的event传入子组件
传入子组件
3、发送事件
发送事件

注意:event.emit方法中可以传第二个参数用来传值,如下:
event.emit('selectAll', 1);
4、在子组件中监听
下面截图中监听事件中this所指对象已经改变,render方法中的this指组件实例,但this.props.event.on方法的回调函数中的this指EventEmitter实例。

子组件
注意:回调函数的参数用来接收父组件发送过来的值,如下:

this.props.event.on('selectAll', function(value) {
  // 参数value即是父组件传过来的值,即value = 1
});
另:第4步截图中监听事件中的回调函数是匿名形式的写法,也可以传入实名参数,如下:

this.props.event.on('selectAll', this.selectAll);
this.props.event.on('cancelAll', this.cancelAll);
需要注意的是,监听事件可以传入匿名函数也可以传入实名函数,但是移除事件的时候,必须传入实名函数,传入匿名函数会有错误

5、移除事件的监听器
componentWillUnmount() {
    this.props.event.removeAllListeners('selectAll', this.selectAll);
    this.props.event.removeAllListeners('cancelAll', this.cancelAll);
}
这里没有用removeListener,而是用了removeAllListeners,这样更保险,因为在多次切换组件时,我发现removeListener并不能很好的移除事件的监听器。另外触发事件是点击等事件时,监听事件最好用once,而不是on。

3.redux&&react-redux

4.context

旧版本context——适用于React版本为16.x之前

祖先组件

 1 import PropTypes from 'prop-types'
 2 
 3 class Child extends Component {
 4     static contextTypes = {
 5       text: PropTypes.string
 6     }
 7     render() {
 8       return <div>{this.context.text}</div>
 9     }
10 }

 

后代组件

 1 import PropTypes from 'prop-types'
 2 class Ancestor extends Component {
 3     static childContextTypes = {
 4       text: PropTypes.string
 5     }
 6     
 7     getChildContext() {
 8         return {
 9             text: 'aaa'
10         }
11     }
12 }

 

新版本context

创建一个全局context

1 import React from 'react'
2 
3 const GlobalContext = React.createContext();
4 
5 export default GlobalContext;

 

子组件

 1 import React, {Component} from 'react'
 2 import GlobalContext from './globalContext' // 导入全局context
 3 
 4 export default class Child extends Component {
 5     render() {
 6         return (
 7             <GlobalContext.Consumer>
 8                 {context => {
 9                     console.log(context)
10                     return (
11                         <div>
12                             <h4>{context.name}</h4>
13                         </div>
14                     )
15                 }}
16             </GlobalContext.Consumer>
17         )
18     }
19 }

 

App.js

import Child from './Component/Child'
import GlobalContext from './globalContext'

render() {
    return (
        <div className="App">
          <GlobalContext.Provider
              value = {{
                name: 'aaa',
              }}>
                <Child /> // 被传递的子组件,可多个
          </GlobalContext.Provider>
    )
}
posted on 2020-08-17 11:22  ygunoil  阅读(470)  评论(0编辑  收藏  举报