Before you're going to hate it, then you're going to love it.html
在 18年的 JSConf Iceland 上, Dan 神提到 Concurrent Render 涉及到 CPU 以及 IO 这两方面。前端
Time Slicing 对应解决左侧的问题, Suspense 对应解决了右侧的问题。它们共同要解决的是的提高用户体验, 在更多的场景下均可以作到可交互
。而 Fiber 架构是上述二者的基石。react
在 16 以前的版本的渲染过程能够想象成一次性潜水 30 米,在这期间作不了其它事情(Stack Reconciler);git
痛点归纳:github
接着拿上面的潜水例子为例,如今变为能够每次潜 10 米,分 3 个 chunk 进行; chunk 和 chunk 之间经过链表链接; chunk 间插入优先级更高的任务, 先前的任务被抛弃。web
开启 Fiber 后,获取异步数据的方法应放到 render 后面的生命周期钩子里(phase 2 阶段)进行, 由于 render 前面的生命周期钩子(phase 1阶段)会被执行屡次编程
注意: 并无缩短原先组件的渲染时间(甚至还加长了),但用户却能感受操做变流畅了。api
requestIdleCallback(): 借力此 api, 浏览器能在空闲的时间处理低优先级的事。数组
Suspense 意思是能暂停当前组件的渲染, 当完成某件事之后再继续渲染。浏览器
import React, { lazy, Suspense } from 'react' const OtherComponent = lazy(() => import('./OtherComponent')) function MyComponent() { return ( <Suspense fallback={<div>loading...</div>}> <OtherComponent /> </Suspense> ) }
一种简单的预加载思路, 可参考 preload
const OtherComponentPromise = import('./OtherComponent'); const OtherComponent = React.lazy(() => OtherComponentPromise);
在 React16 版本中 render() 增长了一些返回类型,到目前为止支持的返回类型以下:
其中 render() 支持返回 Arrays 能让咱们少写一个父节点, 以下所示:
const renderArray = () => [ <div key="A">A</div> <div key="B">B</div> ]
render() 支持返回数组的特性相似 Fragments(16.2), 使用 Fragments 能够不用写 key。
将 React 子节点渲染到指定的节点上
案例:实现一个 Modal 组件,demo
另外关于 Portals 作到冒泡到父节点的兄弟节点这个现象, demo, 我想能够这样子实现:若是组件返回是 Portal 对象,则将该组件的父组件的上的事件 copy 到该组件上。其实并非真的冒泡到了父节点的兄弟节点上。
React 16 提供了一个新的错误捕获钩子 componentDidCatch(error, errorInfo)
, 它能将子组件生命周期里所抛出的错误捕获, 防止页面全局崩溃。demo
componentDidCatch 并不会捕获如下几种错误
服务端渲染通常是做为最后的优化手段, 这里浅显(缺少经验)谈下 React 16 在其上的优化。
在 React 16 版本中引入了 React.hydrate()
, 它的做用主要是将相关的事件注水
进 html
页面中, 同时会比较前端生成的 html
和服务端传到前端的 html
的文本内容的差别, 若是二者不一致将前端产生的文本内容替换服务端生成的(忽略属性)。
在 React 16 版本中, 支持自定义属性(推荐 data-xxx
), 于是 React 能够少维护一份 attribute 白名单, 这也是 React 16 体积减小的一个重要因素。
Context 至关因而用组件化的方式使用 global, 使用其能够共享认证的用户、首选语言(国际化)等一些全局的信息, 而没必要经过组件一层层传递。
如下是比较冗余的传递:
<Page riderId={riderId} /> // ... which renders ... <RiderDetail riderId={riderId} /> // ... which renders ... <RiderLevel riderId={riderId} /> // ... which renders ... <Avatar riderId={riderId} />
在 Context
以前能够传递 <Avatar>
自己(Component Composition 的思想), 写法以下:
function Page(props) { const avatar = <Avatar riderId={props.riderId} /> return <RiderDetail avatar={avatar} /> } <Page riderId={riderId} /> // ... which renders ... <RiderDetail avatar={avatar} /> // ... which renders ... <RiderLevel avatar={avatar} /> // ... which renders ... { props.avatar }
接着是使用 Context
书写的例子, 写法以下:
const RiderContext = React.createContext(1) // 这里为默认值 function Page(props) { const riderId = props.riderId return ( <RiderContext.Provider value={riderId}> <RiderDetail /> </RiderContext.Provider> ) } function RiderDetail() { return <RiderLevel /> } class RiderLevel extends React.Component { static contextType = RiderContext render() { return <Avatar avatar={this.context} />; } }
在将来 17 的版本中,将移除的生命周期钩子以下:
componentWillMount()
: 移除这个 api 基于如下两点考虑:
迁移思路, 将之前写在
componentWillMount
的获取数据、时间订阅的方法写进componentDidMount
中;
componentWillReceiveProps(nextProps)
: 移除这个 api 基于以下考虑:
举个例子: 好比切换 tab 时都要从新获取当前页面的数据, 以前一般会这么作:
componentWillReceiveProps(nextProps) { if (nextProps.riderId !== this.props.riderId) { fetchData() } }
新的钩子 getDerivedStateFromProps()
更加纯粹, 它作的事情是将新传进来的属性和当前的状态值进行对比, 若不一致则更新当前的状态。以前 componentWillReceiveProps()
里的获取数据的逻辑以前提到 Concurrent render
的时候也提到了应该后置到 componentDidUpdate()
中。
getDerivedStateFromProps(nextProps, prevState) { if (nextProps.riderId !== prevState.riderId) { return { riderId: nextProps.riderId } } // 返回 null 则表示 state 不用做更新 return null }
componentWillUpdate()
: 目前将其理解为和 componentWillMount
同样的状况在 React 16.3 的版本中,新加入了两个生命周期:
getDerivedStateFromProps(nextProps, prevState)
: 更加语义化, 用来替代 componentWillMount()
和 componentWillReceiveProps(nextProps)
;
getSnapshotBeforeUpdate(prevProps, prevState)
: 能够将该钩子返回的结果传入 componentDidUpdate 的第三个参数中, 从而达到 dom 数据统一。用来替代 componentWillUpdate();
具体 demo 可见 Update on Async Rendering
React.memo
是一个高阶组件, 它使无状态组件拥有有状态组价中的 shouldComponentUpdate()
以及 PureComponent
的能力。
const MyComponent = React.memo(function MyComponent(props) { ... })
在 React 16.7 以前,React 有两种形式的组件,有状态组件(类)和无状态组件(函数)。Hooks 的意义就是赋能先前的无状态组件,让之变为有状态。这样一来更加契合了 React 所推崇的函数式编程。
接下来梳理 Hooks 中最核心的 2 个 api, useState
和 useEffect
useState 返回状态和一个更新状态的函数
const [count, setCount] = useState(initialState)
使用 Hooks 相比以前用 class 的写法最直观的感觉是更为简洁
function App() { const [count, setCount] = useState(0) return ( <div> <p>You clicked {count} times</p> <button onClick={() => setCount(count + 1)}> Click me </button> </div> ) }
在每次 render 后都会执行这个钩子。能够将它当成是 componentDidMount
、componentDidUpdate
、componentWillUnmount
的合集。所以使用 useEffect 比以前优越的地方在于:
componentDidMount、componentDidUpdate
书写重复的代码;useEffect
;(在之前得写进不一样生命周期里);今年的 React Conf 的一张图, 能够看到 React 从出来到如今势头呈稳健上升趋势, 并在 2018 年这个节点上把 Jquery 拉下了王座。但能够看见 React 将来还有一段很长的路要走。