react进阶第二讲——component

Class组件

在 class 组件中,除了继承 React.Component ,底层还加入了 updater 对象,组件中调用的 setState 和 forceUpdate 本质上是调用了 updater 对象上的 enqueueSetState 和 enqueueForceUpdate 方法。

function Component(props, context, updater) {
  this.props = props;      //绑定props
  this.context = context;  //绑定context
  this.refs = emptyObject; //绑定ref
  this.updater = updater || ReactNoopUpdateQueue; //上面所属的updater 对象
}
/* 绑定setState 方法 */
Component.prototype.setState = function(partialState, callback) {
  this.updater.enqueueSetState(this, partialState, callback, 'setState');
}
/* 绑定forceupdate 方法 */
Component.prototype.forceUpdate = function(callback) {
  this.updater.enqueueForceUpdate(this, callback, 'forceUpdate');
}

Q: 如果没有在 constructor 的 super 函数中传递 props,那么接下来 constructor 执行上下文中就获取不到 props ,这是为什么呢?

/* 假设我们在 constructor 中这么写 */
constructor(){
    super()
    console.log(this.props) // 打印 undefined 为什么?
}

函数组件

不要给函数组件 prototype 绑定属性或方法,因为React 对函数组件的调用,是采用直接执行函数的方式,而不是通过new的方式。

函数组件和类组件本质的区别:

对于类组件来说,底层只需要实例化一次,实例中保存了组件的 state 等状态。对于每一次更新只需要调用 render 方法以及对应的生命周期就可以了。但是在函数组件中,每一次更新都是一次新的函数执行,一次函数组件的更新,里面的变量会重新声明。

组件通信方式

  1. props 和 callback 方式
  2. ref 方式。
  3. React-redux 或 React-mobx 状态管理方式。
  4. context 上下文方式。
  5. event bus 事件总线。

这里指讲解event bus事件总线。

import { BusService } from './eventBus'
/* event Bus  */
function Son(){
    const [ fatherSay , setFatherSay ] = useState('')
    React.useEffect(()=>{ 
        BusService.on('fatherSay',(value)=>{  /* 事件绑定 , 给父组件绑定事件 */
            setFatherSay(value)
       })
       return function(){  BusService.off('fatherSay') /* 解绑事件 */ }
    },[])
    return <div className='son' >
         我是子组件
        <div> 父组件对我说:{ fatherSay } </div>
        <input placeholder="我对父组件说" onChange={ (e)=> BusService.emit('childSay',e.target.value)  }   />
    </div>
}
/* 父组件 */
function Father(){
    const [ childSay , setChildSay ] = useState('')
    React.useEffect(()=>{    /* 事件绑定 , 给子组件绑定事件 */
        BusService.on('childSay',(value)=>{
             setChildSay(value)
        })
        return function(){  BusService.off('childSay') /* 解绑事件 */ }
    },[])
    return <div className="box father" >
        我是父组件
       <div> 子组件对我说:{ childSay } </div>
       <input placeholder="我对子组件说" onChange={ (e)=> BusService.emit('fatherSay',e.target.value) }   />
       <Son  />
    </div>
}
// event.ts
export interface Listener {
    cb: Function
    once: boolean
}

export interface EventsType {
    [eventName: string]: Listener[]
}


export default class OnFire {
    static ver = '__VERSION__'

    es: EventsType = {}

    on(eventName: string, cb: Function, once: boolean = false) {
        if (!this.es[eventName]) {
            this.es[eventName] = []
        }

        this.es[eventName].push({
            cb,
            once,
        })
    }


    once(eventName: string, cb: Function) {
        this.on(eventName, cb, true)
    }

    fire(eventName: string, ...params: any[]) {
        const listeners = this.es[eventName] || []
        let l = listeners.length

        for (let i = 0; i < l; i++) {
            const { cb, once } = listeners[i]

            cb.apply(this, params)

            if (once) {
                listeners.splice(i, 1)
                i--
                l--
            }
        }
    }

    off(eventName?: string, cb?: Function) {
        if (eventName === undefined) {
            this.es = {}
        } else {
            if (cb === undefined) {
                delete this.es[eventName]
            } else {
                const listeners = this.es[eventName] || [];
                let l = listeners.length
                for (let i = 0; i < l; i++) {
                    if (listeners[i].cb === cb) {
                        listeners.splice(i, 1);
                        i--
                        l--
                    }
                }
                console.log(listeners, eventName, 'listeners')
            }
        }
    }

    emit = this.fire
}

export const BusService = new OnFire()

eventBus违背了 React 单向数据流原则,一般不推荐使用。

原文地址:https://www.cnblogs.com/renzhiwei2017/p/15617490.html