reducer
必须是一个纯函数,即没有副作用的函数,不修改输入值,相同的输入一定会有相同的输出state
必须是不可变值,否则在 shouldComponentUpdate
中无法拿到更新前的值,无法做性能优化操作。React.createElement
函数
React.createElement(tag, props, child1, child2, child3)
React.createElement(tag, props, [child1, child2, child3])
vnode
const elem = <div>
<p>aaa</p>
<p style={{ color: 'red' }}>bbb</p>
</div>;
const elem = React.createElement(
"div",
null,
React.createElement("p", null, "aaa"),
React.createElement("p", { style: { color: "red" } }, "bbb")
);
const lisElem = <div>
{
this.state.list.map((item, index) => {
return (<span key={item.id}>
{item.name}
</span>);
})
}
</div>;
const listElem = React.createElement(
"div",
null,
(void 0).state.list.map((item, index) => {
return React.createElement("span", { key: item.id }, item.name);
})
);
react
的事件不是原生事件 MouseEvent
,而是合成事件 SyntheticEvent
react16
是挂载到 document
上的;react17
开始是挂载到 root
上的document
/ root
上进行处理出处:https://coding.imooc.com/lesson/419.html#mid=41943
合成事件的好处:
react-native
document
/ root
上,减少内存消耗,避免频繁解绑出处:https://coding.imooc.com/lesson/419.html#mid=41943
React17
开始挂载到 root
组件上:
- document
只有一个,root
有多个,有利于多个 react
版本共存,例如:微前端
出处:https://coding.imooc.com/lesson/419.html#mid=41943
class ListDemo extends React.Component
constructor(props) {
// ...
}
render() {
// ...
}
increase = () => {
// 开始: 处于 batchUpdate
// isBatchingiUpdates = true
this.setState({
count: this.state.count + 1
});
// 结束
// isBatchingUpdates = false
}
}
class ListDemo extends React.Component
constructor(props) {
// ...
}
render() {
// ...
}
increase = () => {
// 开始: 处于 batchUpdate
// isBatchingUpdates = true
setTimeout(() => {
// 此时 isBatchingUpdates 是 false
this.setState({
count: this.state.count + 1
});
});
// 结束
// isBatchingUpdates = false
}
}
componentDidMount() {
// 开始: 处于 batchUpdate
// isBatchingUpdates = true
document.body.addEventListener('click', () => {
// 此时 isBatchingUpdates 是 false
this.setState({
count: this.state.count + 1
});
console.log('count in body event', this.stae.count);
});
// 结束
// isBatchingUpdates = false
}
哪些能命中 batchUpdate
机制:
React
中注册的事件(和它调用的函数)React
可以“管理”的入口class ListDemo extends React.Component
constructor(props) {
// ...
}
render() {
// ...
}
increase = () => {
// 开始:处于 batchUpdate
// isBatchingUpdates = true
// 其他任何操作
// 结束
// isBatchingUpdates = false
}
}
出处:https://coding.imooc.com/lesson/419.html#mid=41943
transaction.initialize = function() {
console.log('initialize');
};
transaction.close = function() {
console.log('close');
};
function method() {
console.log('abc');
}
transaction.perform(method);
// 输出 'initialize'
// 输出 'abc'
// 输出 'close'
JSX
如何渲染为页面:
props
和 生成 state
render()
函数 生成 vnode
patch(elem, vnode)
:通过 patch
函数将 vonde
更新到 dom
上setState
之后如何更新页面:
setSate(newState)
-> dirtyComponents
(可能有子组件):通过 setState
产生新的 state
,存到 dirtyComponent
进行异步更新render()
函数生成新的 vnode
patch(elem, vnode)
:再通过 patch
函数用 newVnode 去更新旧的 vnodereconciliation
阶段:执行 diff
算法,纯 js
计算commit
阶段:将 diff
结果渲染成 dom
js
是单线程的,且和 dom
渲染共用一个线程dom
操作需求,比如动画、鼠标拖拽等,那么将会卡顿解决方案:fiber
react
内部的运行机制,开发者体会不到reconciliation
阶段进行任务拆分(commit
无法拆分)dom
需要渲染时暂停,空闲时恢复window.requestidleCallback
进行控制(并非所有浏览器支持)JSX
的本质是什么?
jsx
的本质是 React.createElement
函数,执行生返回 vnode
。react
组件更新渲染的过程。
props
和 生成 state
render()
函数生成 vnode
patch
函数将 vonde
渲染成真实 dom
setState
修改产生新的 state
re-render
生成新的 vnode
patch
函数用 newVnode
去更新旧的 vnode
react
为什么要将 patch
过程拆分成 reconciliation
和 commit
两个阶段?
js
是单线程的,且和 dom
渲染共用一个线程dom
操作需求,比如动画、鼠标拖拽等,那么将会卡顿