1.插槽 { this.props.children }
2.IIFE
<div>{(function () { return 'is div'})()}</div>
3.生命周期
组件创建阶段:一辈子只执行一次
componentWillMount【过时】
render
componentDidMount
组件运行阶段:根据 props 或 state 改变,有选择性地执行 0 到多次
componentWillReceiveProps
shouldComponentUpdate
componentWillUpdate
render
componentDidUpdate
组件销毁阶段:一辈子只执行一次
componentWillUnmount
4. Concurrent Mode 可中断渲染:React 不需要阻塞浏览器更新文本输入,相反,它可以让浏览器绘制输入的更新,然后在内存中渲染更新后的列表,当渲染完成后,React 更新 DOM。
React 在 Concurrent 模式中可以中断一项正在执行的更新去做一些更重要的事情,然后再回到之前正在做的工作。
比如中断渲染,继续更新输入框,避免卡顿
在旧屏以合理的 loading 提示等待,在内存中完成新屏的加载和渲染内容,无缝切换,跳过空白。
5. 根据官方文档《不可变数据的力量 immutability》总结
- 在使用 this.setState 时,数组的赋值需要重新定义一个新的数组,使用 concat 等,对象的赋值同理使用 Object.assign({}, ...obj) 等,或者使用 ES6 的扩展运算符。
- PS:在 hook 中我们推荐把 state 切分成多个 state 变量,并永远以非合并的方式去替换,见例子0.5,为抽取自定义 hook 提供便利
- 始终保持原对象,返回新对象,当处理深层嵌套对象时,请参阅 Immer 或 immutability-helper
例子0.5:
// 可以但不推荐 const [state, setState] = useState({ left: 0, top: 0, 100, height: 100 }) setState(state => ({ ...state, left: e.pageX, top: e.pageY })); // 推荐,注意替换的方式,一个新的无关旧 state 的 {} const [position, setPosition] = useState({ left: 0, top: 0 }); const [size, setSize] = useState({ 100, height: 100 }); setPosition({ left: e.pageX, top: e.pageY });
6 ?. 单向数据流:子组件不能直接修改父组件的 state 数据?
- 组件本身无法知道它是来自于
Clock
的 state,或是Clock
的 props,还是手动输入的
7. state 异步更新:千万不要用一个 state 属性去直接计算另一个 state 属性
// Correct // 出于性能考虑,React 可能会把多个 setState() 调用合并成一个调用。 // 因为 this.props 和 this.state 可能会异步更新,所以你不要依赖他们的值来更新下一个状态 // 这个函数用上一个 state 作为第一个参数,将此次更新被应用时的 props 做为第二个参数 this.setState((state, props) => ({ counter: state.counter + props.increment }));
8. 了解 static-getderivedstatefromprops
9 ?.如何避免重渲染
- 子组件 shouldComponentUpdate(nextProps, nextState)
- componentDidUpdate(prevProps, prevState) 比较 prevState.count 和 this.state.count 是否相等
- useEffect(cb, [state/props]可选) 不写默认更新所有状态,若传一个空 [],则表示只在初次渲染和卸载销毁时作用(注意:前提是 useEffect 不涉及 state/props),但不影响非 useEffect 等方法的执行,有时,一个空 [] 会有隐患,如例子 0.9
- useMemo 在组件渲染 过程中 执行
例子 0.9
function Example({ someProp }) { useEffect(() => { function doSomething() { // 假如 doSomething 定义在 useEffect 外部,[someProp] -> [] 则不安全 console.log(someProp); } doSomething(); }, [someProp]); // ✅ 安全(effect 内部声明函数,我们的 effect 仅用到了 `someProp`) }
10. 插件
- 快捷编程 simple react snippets
- prop 数据校验 prop=types
- 动画库 react-transition-group
- 无限滚动 react-virtualized
- 没有嵌套关系的组件之间通信 events
- antd
- redux
- 简化 redux 流程: react-redux + redux
- 中间件向后台请求数据(redux 纯函数禁止异步请求的解决方案): redux-thunk
- 功能同上,替代品: redux-saga
- react-router-dom
- 检测 hook,同时需要配置 .eslintrc.js: eslint-plugin-react-hooks --dev
- swr 异步请求,请求重复数据删除,缓存数据,乐观更新,TS 支持……
- 懒加载组件,代码分割 @loadable/component
- json 显示器 react-json-view
- 富文本编辑器 react-quill
- 拾色器 rc-color-picker
- 二维码生成 qrcode.react
- 数据可视化 antV
- 拖拽库 react-beautiful-dnd
- 表情库 emoji-mart
- 图片裁切 react-image-crop
- 动画 ant motion
- 代码编辑器 react-codemirror2
- 复制到剪切板 react-copy-to-clipboard
11. 最近复习遇到的所有问题,待解决:
- ES6的模块引入是静态分析的,故而可以在编译时正确判断到底加载了什么代码
- 继承 React.Component.prototype.constructor.call(this) // this class 的实例对象
- static propTypes ?
- useEffect,useMemo 缓存,useCallback 缓存的区别
- hook 版是否可替代 redux 呢?:useContext+useReducer
- fiber
12. 跨层级组件通信 Context Api,不推荐
// context.js import React from 'react' let { Consumer, Provider } = React.createContext() export { Consumer, Provider }
12 new: 组件通信 eventEmitter
- useContext 解决组件嵌套太深的问题
- Provider,Consumer,Context
13. renderProps 的妙用
// title: 追逐鼠标的猫 // tips:['render'] 关键字可以自定义,因为 render props 是一种模式,而具体怎么命名是自由的 // class Cat return (<img src="/cat.jpg" style={{ position: 'absolute', left: mouse.x, top: mouse.y }} />) // 核心组件或者可以称之为动态组件,动态 render // class Mouse + prop 的函数校验 return (<div>{this.props.render(this.state)}</div>) Mouse.propTypes = { render: PropTypes.func.isRequired }; // render prop 是一个用于告知组件需要渲染什么内容的函数 prop // 父组件 class MouseTracker return (<Mouse render={mouse => (<Cat mouse={mouse} />)}/>) // 父组件另一种写法,prop 并不真正需要添加到 “attributes” 列表中 return (<Mouse ['attributes']>{mouse => (<p>鼠标的位置是 {mouse.x},{mouse.y}</p>)}</Mouse>)
14. redux 流程
15. hooks 闭包机制
- 每次渲染都会生成一个新的 effect,这正是获取最新 state 而不用担心过期的原因。
- useEffect 可以完成副作用操作:DOM 操作,数据请求,组件更新,订阅
- 与 componentDidMount 或 componentDidUpdate 不同,使用 useEffect 调度的 effect 不会阻塞浏览器更新屏幕
- useEffect 的清除阶段 return fn 有别于组件卸载阶段,每次渲染更新都会清除(总是把握实时的状态,清除时不会出错),不易造成内存泄漏或崩溃;而假如你还在使用 class 组件编程,当你 忘记 在 componentDidUpdate 中 先清除再订阅 时,这正是应用中常见的 bug 来源!
- hook 用于复用状态逻辑,便于单独测试,解决复杂组件充斥复杂逻辑和副作用的问题。
- 带有 hook 的无状态组件称之为'函数组件'
16. 获取 dom
- useRef(null) 获取子组件 dom
- forwardRef((props, childRef) => { return (...) }) 获取子组件中某个元素的 dom
- ref
- createRef