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 方法以及对应的生命周期就可以了。但是在函数组件中,每一次更新都是一次新的函数执行,一次函数组件的更新,里面的变量会重新声明。
组件通信方式
- props 和 callback 方式
- ref 方式。
- React-redux 或 React-mobx 状态管理方式。
- context 上下文方式。
- 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
我是子组件
父组件对我说:{ fatherSay }
BusService.emit('childSay',e.target.value) } />
}
/* 父组件 */
function Father(){
const [ childSay , setChildSay ] = useState('')
React.useEffect(()=>{ /* 事件绑定 , 给子组件绑定事件 */
BusService.on('childSay',(value)=>{
setChildSay(value)
})
return function(){ BusService.off('childSay') /* 解绑事件 */ }
},[])
return
我是父组件
子组件对我说:{ childSay }
BusService.emit('fatherSay',e.target.value) } />
}
// 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 单向数据流原则,一般不推荐使用。