前言:阅读官方文档,可以跟着作者的思路,去了解框架的整体结构和基础知识。不经间透露出的设计思想和作者对知识点的深入浅出的描述,都会让人受益匪浅。本文是对官方文档的总结、归纳,方便后续的查阅复习,也有本人主观的一些理解。
一、核心概念
JSX语法:
JSX语法诞生的原因:
- react是一个JS库,更方便操作JS对象
- DOM的频繁操作会增大浏览器的性能开销
- 如何能即写HTML标签,又可以把它当成JS对象去操作
JSX语法的本质:
- JSX其实是react.createElement(componentName, props, ...children)的语法糖,映射为虚拟DOM
下面官网3张图,生动表现了,JSX的解析过程(JSX映射为虚拟DOM对象)
JSX的安全性:
- 渲染输入的内容时,会转换为字符串,可以防止XSS攻击(cross-site-scripting跨站脚本)
关于Props和State数据的生动解释:
- React中的Props数据就像瀑布中的水流,自上而下,而State可以在任意一点上给瀑布增加额外的水源
props数据:
- 外部传入组件的,只读数据
state数据:
-
组件作用域的数据
-
setState()方法的细节:
1. React会把多个setState()合并成一个,用以提升性能。 2. React的this.props和this.state可能会异步更新 3. 保证拿到前一刻的state和props的方式: this.setState((state,props) => { counter: state.counter + props.increment }) 注意: setState()当前是同步方法, 因为React的实现机制导致了异步的错觉, 放入setTimeout中超脱React执行流时,可以看到时同步执行的
关于事件处理:
- 推荐用法:onClick={this.arrowFunc(this, id)}(arrowFunc是箭头函数的引用,这样每次不会每次render()时,生成新的函数,同时this也默认绑定到了组件上)
- 兼容问题:使用SyntheticEvent包装器,即浏览器的原生事件的包装器(拥有浏览器所有原生事件的接口,兼容所有浏览器)
react的slot实现:
-
默认slot:
return (<div>{props.children}</div>)使用:组件标签内的 所有内容 替换 {props.children} -
具名slot:
return (<div><div>{props.left}</div><div>{props.right}</div></div>)使用:组件标签中的 left对象 替换 {props.left} / right对象 替换 {props.right}
key属性的作用:
-
标识DOM的唯一性(带来的好处):
1. 便于diffing算法找出最小的更新,减少开销 2. 也可以修改key,强制更新
.
二、高级指引
无障碍:
- 示例:Accessibility => a11y (例如 HTML 属性 aria-* 屏幕阅读器使用 )
代码分割:
-
概念:将代码分包,只有使用到这个代码包才去加载
-
优点:减少不必要代码的加载,提升响应速度
-
实践:
1. 微信小程序的分包配置 2. vue react 前端框架支持的路由动态加载
context:
-
概念:父组件的数据,提供给所有子组件使用,所有子组件都能访问到这些数据
-
用法:
创建context:
ThemeContext = React.createContext('light');父组件中提供context:
<ThemeContext.Provider value="dark">父组件</ThemeContext.Provider>子组件中获取context:
-
class组件:
组件内
static contextType = ThemeContext;组件外
MyClass.contextType = ThemeContext; -
函数组件:
<ThemeContext.Consumer>函数组件(context)</ThemeContext.Consumer>
-
-
优点:减少props的层层传递
-
缺陷:增加了父子组件的耦合,不便于子组件的复用
错误边界:
- 使用 static getDerivedStateFromError() 渲染备用 UI
- 使用 componentDidCatch() 打印错误信息
Refs:
-
推荐用法:
class组件内:
React.createRef()函数组件内:
useRef(initialValue) -
过时用法:
this.refs.textInput -
refs使用的地方:
HTML元素:current上挂载DOM对象
class组件:current上挂载class组件的实例对象
函数组件:配合forwardRef、useImperativeHandle,current上可以挂载函数组件的属方
-
Refs转发:
class组件:直接做为属性,穿透class,给到子组件
函数组件:配合forwardRef,在内部获取到,给到子组件
-
Refs回调用法(class组件和函数组件都适用):
原理:使用函数,去获取组件/DOM的引用
示例:
ref={el => this.inputElement = el}
Fragments:
- 一个包裹性的占位标签,原生写法React.Fragment(可以支持key属性),简写<></>
高阶组件:
- 它应该是一个纯函数组件,接受一个组件参数,返回一个新的组件
深入JSX:
-
本质:JSX其实是react.createElement(componentName, props, ...children)的语法糖,其实本质本质就是虚拟DOM
-
语法:
组件名:
- 必须是大写字母开头
- 不能使用通用表达式(通用表达式即:对象[变量名])
属性值:默认值是true
子元素:可以将任何东西作为子元素传递给自定义组件
-
不会渲染的值:true,false, undefined, null 是合法的子元素。但它们并不会被渲染
性能优化:
-
DOM更新提速的方式:
-
使用shouldComponentUpdate(nextProps, nextState)生命周期函数(默认返回ture)
原理:通过返回是true/false,控制DOM是否更新(但影响不到它的子组件)
-
继承React.PureComponent,使用浅比较,控制DOM更新
原理:浅比较props和state,是否变化来控制DOM更新(更深层的引用,察觉不到)
-
createPortal:
- 作用:给任意DOM节点,添加子节点(ReactDOM.createPortal(child, container))
- 副作用:createPortal方法添加的子节点,结构上属于被添加到的父节点上,事件上又属于它之前的位置
Profiler组件:
-
作用:测量该组件内的DOM渲染花销
-
用法:
<Profiler id="Navigation" onRender={callback}>被测量的DOM</Profiler>onRender函数的作用:获取渲染花销的具体数据
Render Props:
- 本质:函数作为属性传递进父组件,该函数返回使用父组件数据的子组件
- 作用:实现了类似高阶组件的功能,父组件可以接受不同的子组件,并返回新组件
严格模式:
-
作用:突显应用程序中潜在问题的工具
-
潜在问题的类型:
- 不安全的生命周期(比如componentWillMount())
- 使用过时字符串 ref API 的警告
- 过时的 context API
- 使用废弃的 findDOMNode 方法的警告
- 意外的副作用
-
示例:
<React.StrictMode>被严格模式检查的内容</React.StrictMode>
使用 PropTypes 类型检查:
-
用法:
import PropTypes from 'prop-typesclass组件名/函数组件名.propTypes = { name: PropTypes.string }
输入组件的类型:
-
非受控组件:
本质:数据通过ref,交给DOM节点管理(获取方式this.inputRef.current.value)
-
受控组件:
本质:传统用法,数据通过表单事件,交给state管理 .
三、React class 组件的API
生命周期中的API调用顺序:
-
挂载时:
constructor()-
作用:
初始化
this.state为函数绑定this
this.handleClick = this.handleClick.bind(this);
static getDerivedStateFromProps()(不常用)-
作用:
在render()前调用,返回一个对象来更新state,返回null则不更新
render()-
作用:
通常是返回react元素(组件、jsx)
-
特点:
class组件中唯一必须实现的方法
它是纯函数,输出结果只受state/props的影响
componentDidMount()-
作用:
在组件挂载后,浏览器更新屏幕前,去执行额外的数据请求、DOM操作
-
-
更新时:
static getDerivedStateFromProps()(上面已解释)shouldComponentUpdate()(不建议用)-
作用:
根据 props 或 state 的变化,判断是否更新当前组件,但对子组件的更新无影响(不建议用的原因)
-
特点:
当 props 或 state 发生变化时,会在render()之前被调用。返回值默认为 true。
返回false时,后续的 render() 和 componentDidUpdate() 不会调用
render()(上面已解释)getSnapshotBeforeUpdate()(不常用)-
作用:
在最近一次渲染前调用,可以获取更新前的DOM信息
-
特点:
返回的值会给到componentDidUpdate()
componentDidUpdate()-
作用:
更新后会被立即调用,可以在条件语句里执行一些 数据请求、DOM操作
-
-
卸载时:
componentWillUnmount()-
作用:
组件卸载时,做一些清除副作用的操作
-
-
生命周期中出错时:
getDerivedStateFromError()(未来版本,可能会使用)-
作用:
捕获渲染阶段错误,可用来渲染备用UI
componentDidCatch()(当前版本,建议使用)-
作用:
捕获提交阶段错误,可用来打印错误信息
-
其他API:
setState()
-
作用:
给组件内作用域的state,设置值
-
特点:
当前是同步方法,容易被react的执行机制误导为异步方法
forceUpdate()(不建议使用,尽量用state、props的变化驱动组件渲染)
-
作用:
使组件调用render(),强制组件重新渲染
Class 属性:
defaultProps:
-
作用:
给class组件,添加默认的props
displayName
-
作用:
调试消息时,高阶组件中区分子组件的名称
.
四、ReactDOM的API
render()
-
作用:
浏览器端渲染组件
hydrate()
-
作用:
貌似是服务端渲染, 它用于在 ReactDOMServer 渲染的容器中对 HTML 的内容进行 hydrate 操作(后续加强了解)
unmountComponentAtNode()
-
作用:
从 DOM 中卸载组件
findDOMNode()
-
作用:
访问底层 DOM 节点的应急方案,不推荐使用的API
createPortal()
-
作用:
将子节点渲染到 DOM 节点中的方式(产生的副作用已在上面说明)
.
五、ReactDOMServer
-
原理:
在Node服务端,将react组件,渲染成静态标记
-
作用:
服务端渲染,提升首屏加载速度,和seo优化
-
常用API:
renderToString()-
作用:
将react组件,渲染成HTML字符串
enderToStaticMarkup()-
作用:
将react组件,渲染成HTML字符串,会去除额外的属性
renderToNodeStream()-
作用:
将react组件,渲染成HTML字符串的可读流
renderToStaticNodeStream()-
作用:
将react组件,渲染成HTML字符串的可读流,会去除额外的属性
-
.
六、React的DOM系统
-
兼容:
兼顾性能的同时,兼容所有浏览器
-
属性:
属性名称,小驼峰的方式
在HTML属性的基础上,也有一套自己的定义的属性 .
七、其它
-
mixins被抛弃的原因:
1.mixins中的隐式依赖 2.mixins之间的依赖关系混乱 3.mixins之间的函数命名的冲突
.
写在最后:以上就是阅读官方文档后,总结的内容,可以作为复习纲要,更细节深入的内容可以以此进行搜索查阅。