React

170 阅读6分钟

1. 为什么React

React 是Facebook 2011开发的,是JavaScript MVC框架下的应用,MVC将应用分为三个部分:数据层,视图层和控制层。React 主要用于构建UI,属于视图层。

image.png

"Learn React Once and Write Everywhere" - Reactjs.org

  • React 灵活的用于组件化开发,你可以把一个按钮 / 表单等等抽成一个组件。 React 既可以编写Web应用,也可以使用React Native开发 apps。
  • 相比于其他的框架,react开发更简单。通过函数式编程结合JSX语法,可以极大减少代码量。下面对比了Angular, Vue.js和React在代码循环的写法,可以看到react写法更接近原生的JS。

Angular Loop Vue.js Loop image.png

  • React 有Facebook支持和广泛的社区支持

React GitHub已有164K的star,是GitHub Top5的仓库。

image.png

React 的 NPM 包每周也有数百万次下载。

image.png

  • React 性能优化。React开发团队意识到JS本身很快,但是更新DOM会导致JS变慢,因此React使用最高效和最智能的方式优化DOM更改次数。主要通过虚拟DOM和conCurrent mode来实现,见2.1和2.7。

1.1 MVC & MVP & MVVM

MVC, MVP和MVVM是软件架构设计模式,是解决某一类问题而抽象出来的方法。

image.png

1.2 React相比于原生JS

  • 模块化开发
  • 不用写原生DOM操作,通过虚拟DOM优化性能
  • UI = f(data) 函数式编程

1.3 单向数据流

自顶向下,单向数据流是react的特点之一,state只能向下传递。

2. React使用

2.1 虚拟DOM & diff & fiber

  • 虚拟DOM是真实DOM的映射,是一种树形结构,可以理解为真实DOM和JS之间的缓存,保存了真实DOM一些基本属性和关系。
  • diffing算法。react会维护两颗虚拟DOM树,一颗保存当前状态,另外一颗渲染更新后状态,通过比较两棵树的差异,进行DOM修改,比较的方法就是diffing算法。React diffing核心思想是增量式渲染。通过对比新的列表中的节点,在原本的列表中的位置是否是递增,来判断当前节点是否需要移动,将时间复杂度优化到O(n)。diffing算法通过key来进行比较,因此key需要唯一,不建议使用下标作为key。
  • fiber(协程)是React16中的新的协调引擎,目的是使得虚拟DOM可以增量式渲染。核心思想是,适时的让出cpu执行权,执行更高权限的事件,让用户不感觉卡顿。结合concurrent mode (requestIdleCallback和requestAnimationFrame) 来实现cpu调度。

2.2 JSX

JSX是是JavaScript XML,React提供的JS语法糖。实际上引入React后可以再JS中写HTML。JSX将XML语法加入到JavaScript中,在JS中写了JSX将会被预处理成React Element

  • JSX中可以写常规HTML,可以通过{props}往html中插入变量JS表达式,或者带参数的函数{func(props)}。
  • JSX编译后,是一个函数调用,返回值为JS对象,JSX可以作为表达式,如IF判断。
  • 可以再标签中添加属性,属性若为字符串,则加上引号,若为对象或表达式,加上{},属性key使用驼峰命名(JSX中className,没有class)
  • 可以单闭合 <img/>
  • 可以给html添加类但class需改写成className 为什么React要创建JSX: 渲染的逻辑处理与UI逻辑其实是耦合的, event, state, data互相关联,既然如此,那么就把html标记语言与逻辑处理相关的js内容放在一起,组成一个松耦合的模块,这个模块就是JSX元素。 JSX使用: 首先怎么才能写JSX呢,在普通的JS文件中需引入react,reactDOM(若要对DOM进行操作)以及babel或者通过Babel在线编译 JSX防范XSS攻击: XSS是跨站脚本注入攻击。
    • 由于当你尝试通过{html}进行插入html代码时, React会自动将html转为字符串,故React可部分防止XSS攻击
    • JSX中是通过传入函数作为事件处理方式,而不是传入字符串,字符串可能包含恶意代码
    • JSX无法抵御XSS攻击: 如:<a href="{...}" />, <img src={...} />, <iframe src="{...} />,css注入style={...} prop,,或者通过设置a的href为javascript:xxx,以及使用base64 编码的数据进行替换,又或从用户处接受了被恶意控制的props。

2.3 组件通信

  • 父子: 父组件通过props传递,子组件通过父组件传递回调改变自身一些状态(隐藏)。
  • 跨级: 层层传递props(麻烦) / context(污染组件) / redux。
  • 没有关系的组件: redux / 发布订阅模式。

2.4 setState 同步 & 异步

从API的角度来看应该是同步的,但React自己不保证setState之后能够立即拿到改变后的结果。 setState 在 React 能够控制的范围被调用,它就是异步的。比如合成事件处理函数, 生命周期函数, 此时会进行批量更新, 也就是将状态合并后再进行 DOM 更新。 如果 setState 在原生 JavaScript 控制的范围被调用,它就是同步的。比如原生事件处理函数中, 定时器回调函数中, Ajax 回调函数中, 此时 setState 被调用后会立即更新 DOM 。 因为异步实际上是对性能的优化。unstable_batchedUpdates 可以实现强制的批量更新。

2.5 生命周期

  • componentWillMount() 渲染前调用,只触发一次
  • componentDidMount() 渲染后调用,此时DOM已经生成,通过this.getDOMNode()访问。
  • componentWillReceiveProps 在组件接收到一个新的 prop (更新后)时被调用。
  • shouldComponentUpdate 返回Boolean,在组件接收到新的props或者state时被调用。
  • componentWillUpdate 在组件接收到新的props或者state但还没有render时被调用。
  • componentDidUpdate 完成更新后调用。
  • componentWillUnMount 组件卸载时调用。
  • getDerivedStateFromError

2.6 React Hooks

函数式组件,React16.8新增特性,目的是提高组件的复用,解决类式组件组件复杂性,增加符合函数式编程中的代数效应,用于将副作用从函数中分离。

常用hooks

  • useState,返回一个数组,第一参数为state,第二个参数为setState。不能在if / for里使用,会导致state被覆盖。
const [state, setState] = useState(initialState)
  • useEffect,集合componentDidMount,componentDidUpdate,componentWillUnMount生命周期。接收一个数组作为依赖项,在依赖项改变时调用fn,如果不传,则在每次componentDidUpdate会触发,如果传空数组,componentDidMount触发。
useEffect(fn, [])
  • useLayoutEffect,类似于useEffect,但会阻塞页面渲染。
  • useContext,它是以 Hook 的方式使用 React Context。
const context = useContext(Context)
  • useReducer,语法糖跟reudx差不多
const [state, dispatch] = useReducer(reducer, initialArg, init)
  • useRef
  • useMemo, 常用的性能优化hook, 返回缓存变量,减少不必要渲染。
const memoizedValue = useMemo(() => computeExpensiveValue(a, b), [a, b]);
  • useCallback,常用的性能优化hook, 返回缓存函数,减少不必要渲染。
const memoizedCallback = useCallback( () => { doSomething(a, b); }, [a, b], );
  • 自定义hook,通过use开头,有变量和set方法。

2.7 Redux

redux 是React的一个全局状态管理库,简化react中的单向数据流。

  • action: JSON 对象,type和payload键
  • dispatch: 分发
  • reducer: 纯函数,将当前state和action作为参数,返回新的state。 image.png

2.7 提高性能

  • 适当使用shouldComponentUpdate,减少组件渲染。
  • hooks中useMemo,useCallBack。
  • 循环时使用唯一的key。

引用

Why You Should Use React.js For Web Development

MVC, MVP and MVVM Design Pattern

React、Vue2、Vue3的三种Diff算法

React fiber

# React Concurrent 模式抢先预览上篇: Suspense the world