1. React生命周期
- 单个组件的生命周期
1.componentwillMount
(React17废弃)
2.componentDidMount
3.componentWillReceiveProps
(React17替换成getDerivedStateFromProps
)
4.shouldComponentUpdate
5.componentWillUpdate
(React17替换成getSnapshotBeforeUpdate
)
6.componentDidUpdate
7.componentWillUnmount
- 父子组件的生命周期
大致和Vue相同,不同的是,react没有局部更新,更新父组件的同时也会更新子组件。
1.挂载:父componentWillMount -> 子componentWillMount -> 子componentDidMount -> 父componentDidMount
2.销毁:父componentWillUnmount -> 子componentWillUnmount
3.更新
(1)只更新子:子shouldComponentUpdate -> 子componentWillUpdate -> 子componentDidUpdate
(2)更新父或同时更新:父shouldComponentUpdate -> 父componentWillUpdate -> 子componentWillReceiveProps-> 子shouldComponentUpdate -> 子componentWillUpdate -> 子componentDidUpdate -> 父componentDidUpdate
2. React17 生命周期改动
componentWillMount
componentWillRecieveProps
componentWIllUpdate
简单来说就是这三个生命周期函数容易被误解并滥用,可能会对异步渲染造成潜在的问题。可用UNSAFE_xxx
来取消eslint
的报错。
- 新增三个生命周期
1.getDerivedStateFromProps(nextProps, prevState)
静态方法,所以不能使用this.setState。 用于替换componentWillReceiveProps
,可以用来控制 props
更新 state
的过程;它返回一个对象表示新的 state
;如果不需要更新,返回 null
即可
2.getSnapshotBeforeUpdate(nextProps, prevState) 。用于替换componentWillUpdate
3.componendDidCatch(error, info)。新增,用于捕捉错误
3. React的通信方式
props
context。可跨级通信,但不知道来源哪里不推荐使用。基于生产者消费者模式
redux和react-redux
用js实现发布订阅模式
React17 会废弃childContext 使用新API - createContext(),并提供Provider和consumer组件,类似Vue
4. setState
setState
是React
组件中用于更新数据和触发渲染的函数,他的用法如下
this.setState(newState:object | updater: Function, callback?)
updater = (state, prop) => {}
- 同步和异步
setState
,何时同步,何时异步?
1.在react的生命周期勾子或react事件监听回调中使用
2.其他情况,如定时器回调,原生事件监听回调,promise回调
- 为什么setState是异步的?
setState
出发React
的更新生命周期函数4个函数:shouldComponentUpdate
,componentWillUpdate
,render
,componentDidUpdate
。如果每一次setState
调用都走一圈生命周期,并拿render
函数返回的结果会拿去做Virtual DOM比较和更新DOM树,这个就比较费时间。目前
React
会将setState
的效果放在队列中,积攒着一次引发更新过程。为的就是把 Virtual DOM 和 DOM 树操作降到最小,用于提高性能。
- setState如何实现
ReactComponent.prototype.setState = function (partialState, callback) {
// 更新的操作会放在数组里
this.updater.enqueueSetState(this, partialState);
if (callback) {
this.updater.enqueueCallback(this, callback, 'setState');
}};
- 总体流程如下:
1.将state
放入enqueueSetState
队列中,并调用enqueueUpdate
处理要更新的Component
2.如果组件当前正处于update
中(isBatchingUpdates
),则先将Component
存入dirtyComponent
中。否则调用batchedUpdates
处理。
3.batchedUpdates
发起一次transaction.perform()
事务
4.事务会更新isBatchingUpdates
为false
,循环遍历所有的dirtyComponents
,调用updateComponent
刷新组件,并执行它的pendingCallbacks
, 也就是setState
中设置的callback
。
5. React的事件机制
- 合成事件
1.在react
中使用jsx语法绑定的事件并不是原生事件,而是一种合成事件SyntheticEvent
。例如SyntheticEvent
, SyntheticKeyboardEvent
, SyntheticFocusEvent
等。他有以下特点:
2.默认的事件流是冒泡,如果以捕获的方式来触发事件的话,事件类型后面加一个后缀Capture
几乎所有的事件代理(delegate
)到document
,达到性能优化的目的,例如对于audio
、video
标签,存在一些媒体事件(例如onplay
、onpause
),只能在这些标签上进行事件绑定,绑定一个入口分发函数(dispatchEvent
)
3.对于每种类型的事件,拥有统一的分发函数dispatchEvent
4.事件对象(event
)是合成对象(SyntheticEvent
),不是原生的。所以e.stopPropagation()
方法阻止的知识合成事件流的传播。
- 如何实现
React 事件机制分为事件注册,和事件分发,两个部分。
1.组件加载 (mountComponent
)、更新 (updateComponent
) 的时候,调用 _updateDOMProperties
方法对 props
进行处理,将事件绑定在document
上,并存储在EventPluginHub
中(订阅发布中心)
2.回调统一是ReactEventListener
的dispatch
方法。通过_dispatchListeners
里得到所有绑定的回调函数,然后循环执行里面的所有的回调函数
6. React16
新的核心算法 Fiber
render
可以返回数组,字符串错误处理机制
Portals
组件 渲染外部的dom节点.createPortal API
更好 更快的服务端渲染
rendertoNodeStream
返回node
的流体积更小 MIT协议
7. Fiber
Fiber
可以提升复杂React
应用的可响应性和性能。Fiber
即是React
新的调度算法。每次有
state
的变化React
重新计算,如果计算量过大,浏览器主线程来不及做其他的事情,比如rerender
或者layout
,那例如动画就会出现卡顿现象。React
制定了一种名为Fiber
的数据结构,加上新的算法,使得大量的计算可以被拆解,异步化,浏览器主线程得以释放,保证了渲染的帧率。从而提高响应性。React
将更新分为了两个时期:
1.render/reconciliation
: 可打断,React
在 workingProgressTree
上复用 current
上的 Fiber
数据结构来一步地(通过requestIdleCallback
)来构建新的 tree
,标记处需要更新的节点,放入队列中。
2.commit
: 不可打断。在第二阶段,React
将其所有的变更一次性更新到DOM上。
8. 函数式组件,class组件,受控组件,高级组件的概念
class
组件:类组件不仅允许你使用更多额外的功能,如组件自身的状态和生命周期钩子,也能使组件直接访问store
并维持状态函数式组件:当组件仅是接收
props
,并将组件自身渲染到页面时,该组件就是一个 '无状态组件(stateless component
)',可以使用一个纯函数来创建这样的组件,即函数式组件受控组件:在 HTML 中,类似
input, textarea
和select
这样的表单元素会维护自身的状态,并基于用户的输入来更新。一个输入表单元素,它的值通过React
的这种方式来控制,这样的元素就被称为"受控元素"。高级组件HOC:高阶组件是一个以组件为参数并返回一个新组件的函数,例如:
redux的connect函数
9. React-router
BrowserHistory:h5历史模式
HashHistory:h5 hash模式
MemoryHistory:和abstract模式类似
StaticRouter:一个永远不会改变位置的<Router>。这在服务器端渲染场景中非常有用
NativeRouter:RN使用
10. Redux
state
: 数据,即状态Action
: 一个纯对象,携带这个操作的类型和数据信息Action Creater
: 一个函数,根据指定参数,来生成一个Action
,目的是减少代码量Reducer
: 一个纯函数,用来修改应用的状态,接收当前State
和Action
,返回一个新的State
。
1.不得改写参数
2.不得调用系统的I/O的API
3.不得调用Date.now()
或者Math.random()
等不纯的方法,因为每次得到的结果会不一样
4.不能改变State
,必须返回一个新的对象,具体可以使用{...obj}
运算符或者Object.assign()
来操作
combineReducers
: 一个函数,将多个小的Reducer
合并成一个大的Reducer
Store
: 数据存储中心
1.Store.getState()
获取Store
当前的状态
2.Store.dispatch()
分派一个Action
,用来修改Store
的状态,从View中发出Action的唯一方法
3.Store.subscribe()
订阅一个监听器,当Store
的状态发生改变的时候,执行函数
-
Middlewares
: 中间件, 中间件实际上就是一个拦截器,本质是一个函数,拦截所有的Action,并执行特定的操作
compose
函数,将[f1, f2, f3] => f1(f2(f3(x)))
11. Redux数据流
- Redux 应用中数据的生命周期遵循下面 4 个步骤:
调用 store.dispatch(action)。
Redux store 调用传入的 reducer 函数。
根 reducer 应该把多个子 reducer 输出合并成一个单一的 state 树。
Redux store 保存了根 reducer 返回的完整 state 树。
# Node.js
1. eventloop
- 基本流程
1.timers:执行满足条件的setTimeout、setInterval回调。[uv__run_timers函数]
2.I/O callbacks:是否有已完成的I/O操作的回调函数,来自上一轮的poll残留。[uv__run_pending函数]
3.idle,prepare:node内部特定的阶段,在I/O轮询开始前做一些特定的回调,可忽略 [uv__run_idle, uv__run_prepare函数]
4.poll:轮询,等待还没完成的I/O事件,会因timers和超时时间等结束等待。[uv__io_poll(loop, timeout)函数]
5.check:执行setImmediate的回调。[uv__run_check函数]
6.close callbacks:关闭所有的closing handles,一些onclose事件,例如7.socket.on("close",func)。[ uv__run_closing_handles(loop)函数]
重复以上步骤。
- 经典例子
浏览器环境:time1,promise1,time2,promise2
node11以下:time1,time2,promise1,promise2
node11及以上:time1,promise1,time2,promise2
在 node 11 版本中,node 下 Event Loop 已经与浏览器趋于相同。我们可以用浏览器的微任务和宏任务解释,11版本前的timer,由于到期时间相近,会在timer阶段合并执行。所以打出time1后,打印time2。
2. koa 洋葱模型
- koa洋葱式模型: koa各个中间件合并执行,结合next()形成一种串行机制,并且是支持异步。如请求顺序进入1,2,3,4,响应顺序从4,3,2,1出来
1.compose函数支持中间件和next
2.async/await支持异步
- 洋葱模式实现了:
1.context的保存和传递
2.中间件的管理和next的实现