就像人们对更新移动应用程序和操做系统感到兴奋同样,开发人员也应该对更新框架感到兴奋。不一样框架的新版本具备新特性和开箱即用的技巧。html
下面是将现有应用程序从 React 15 迁移到 React 16 时应该考虑的一些好特性。前端
想阅读更多优质文章请猛戳GitHub博客,一年百来篇优质文章等着你!react
React 16 引入了错误边界的新概念。git
如今在React 16中,你们就能使用错误边界功能,而不用一发生错误就解除整个程序挂载了。把错误边界当作是一种相似于编程中try-catch语句的机制,只不过是由 React 组件来实现的。github
错误边界是一种React组件。它及其子组件造成一个树型结构,能捕获JavaScript中全部位置的错误,记录下错误,而且还能显示一个后备界面,避免让用户直接看到组件树的崩溃信息。编程
这里涉及到一种新的生命周期函数叫componentDidCatch(error, info)
。不管什么样的类组件,只要定义了这个函数,就成为了一个错误边界。segmentfault
class ErrorBoundary extends React.Component { constructor(props) { super(props); this.state = { hasError: false }; } componentDidCatch(error, info) { // Display fallback UI this.setState({ hasError: true }); // 你还能够将错误记录到错误报告服务中 logErrorToMyService(error, info); } render() { if (this.state.hasError) { // 能够渲染任何自定义回退界面 return <h1>Something went wrong.</h1>; } return this.props.children; } }
也能够将其用做常规组件使用:数组
<ErrorBoundary> <MyWidget /> </ErrorBoundary>
componentDidCatch()
方法的工做原理相似于JavaScript catch{}
块,但它适用于组件。只有类组件能够是错误边界。实际上,在大多数状况下,你都但愿声明一次错误边界组件,而后在整个应用程序中使用它。安全
请注意,错误边界只会捕获位于它们之下的组件中的错误。错误边界没法捕获到自身的错误。若是错误边界渲染错误消息失败,错误将被传播到上方最接近的错误边界。这也相似于 JavaScript 中的 catch{}块。框架
有了错误边界,即便某个组件的结果有错误,整个React程序挂载也不会被解除。只有出错的那个组件会显示一个后备界面,而整个程序仍然彻底正常运行。
关于错误边界更多的内容可查看官网。
如今,在渲染时能够摆脱将组件包装在 div
中。
你如今能够从组件的 render 方法返回元素数组。与其余数组同样,你须要为每一个元素添加一个键以免发出键警告:
render() { // No need to wrap list items in an extra element! return [ // Don't forget the keys :) <li key="A">First item</li>, <li key="B">Second item</li>, <li key="C">Third item</li>, ]; }
从React 16.2.0开始,它支持JSX的一个特殊片断语法,该语法不须要键。
render() { return ( <> <ChildA /> <ChildB /> <ChildC /> </> ); }
支持返回字符串:
render() { return 'Look ma, no spans!'; }
Portal 提供了一种将子节点渲染到父节点以外的 dom 节点。
ReactDOM.createPortal(child, container)
第一个参数 (child
)是任何可渲染的 React子元素,例如元素,字符串或片断。 第二个参数 (container)
是 DOM 元素。
在 React15.X 版本中,咱们只能讲子节点在父节点中渲染,基本用法以下:
render() { // React须要建立一个新的div来包含子节点 return ( <div> {this.props.children} </div> ); }
可是若是须要将子节点插入到父节点以外的dom呢,React15.x 及以前都没有提供这个功能的 API。
可使用 React16.0 中的 portal:
render() { // React不须要建立一个新的div去包含子元素,直接将子元素渲染到另外一个 //dom节点中 //这个dom节点能够是任何有效的dom节点,不管其所处于dom树中的哪一个位置 return ReactDOM.createPortal( this.props.children, domNode, ); }
Portal 的一个典型用例是这样的:当父组件带有 overflow:hidden
或 z-index
样式时,你但愿子组件在视觉上可以“突破”它的容器。例如,对话框、悬停卡和工具提示。
React15 会忽略任何未知的 DOM 属性。React 会跳过它们,由于没法识别它们。
// 你的代码 <div mycustomattribute="something" />
React 15 将渲染一个空的 div:
// React 15 output: <div />
在 React16 中,输出将以下所示(会显示自定义属性,而且彻底不会被忽略)
// React 16 output: <div mycustomattribute="something" />
有时候咱们须要经过函数来判断组件状态更新是否触发从新渲染,在 React 16 中,咱们能够经过调用 setState
时传入 null
来避免组件从新渲染,这也就意味着,咱们能够在 setState 方法内部决定咱们的状态是否须要更新,
const MAX_PIZZAS = 20; function addAnotherPizza(state, props) { // Stop updates and re-renders if I've had enough pizzas. if (state.pizza === MAX_PIZZAS) { return null; } // If not, keep the pizzas coming! :D return { pizza: state.pizza + 1, } } this.setState(addAnotherPizza);
更多相关信息请阅读这里
如今使用 React16 建立refs
要容易得多。 为何须要使用refs
:
ref
是使用 React.createRef()
建立的,并经过 ref
属性附加到 React 元素。ref
一般是在构造组件时被分配给实例的属性,以便在整个组件中引用它们。
class MyComponent extends React.Component { constructor(props) { super(props); this.myRef = React.createRef(); } render () { return <div ref={this.myRef}></div> } }
上述是建立Ref
指向的方法, 在Ref 所指向的组件,在render
后就能够调用,React16.3 中提供了current
属性,用于引用render
后的节点:
componentDidMount(){ console.log(this.myRef.current); //render以后就能够输出该ref指向的那个节点 }
此外,一样的 Ref 所指向的节点能够是 dom 节点,也能够是类组件。
Ref 的值因节点的类型不一样而有所不一样:
Context 提供了一种经过组件树传递数据的方法,无需在每一层手动传递 prop
。
const { Provider, Consumer } = React.createContext(defaultValue)
建立{Provider,Consumer}
对。当 React 渲染 Consumer 时,它将从树中最接近的 Provider 读取当前上下文值。
defaultValue
参数只在消费者在树中找不到匹配的 Provider 时才会用到,这在单独测试组件时十分有用。注意:将 undefined
做为 Provider 值传递进去并不会致使 Consumer 使用 defaultValue
。
<Provider value={/* some value */}>
一个容许 Consumer 订阅上下文变动的 React 组件。
一个 Provider 能够链接多个 Consumer,能够在树中嵌套 Provider,实现更深的值覆盖。
<Consumer> {value => /* render something based on the context value */} </Consumer>
订阅上下文更改的 React 组件。
须要一个函数做为子组件。这个函数接收当前上下文值,并返回一个 React 节点。传给函数的 value 参数将等于树中最近的 Provider
的 value
。若是没有匹配的 Provider,则 value
参数将等于传给 createContext()
的 defaultValue。
在很长一段时间内,componentWillReceiveProps
是在没有附加渲染的状况下更新状态的惟一方法。
在版本16.3中,咱们引入了一个全新的生命周期函数getDerivedStateFromProps
用来替换componentWillReceiveProps
,并用更安全的方式处理相同的场景。
与此同时,咱们意识到人们对如何使用这两种方法有不少误解,咱们发现了一些反模式,这些错误致使了微妙而使人困惑的bug。
在16.4中,有关getDerivedStateFromProps
的修复使得派生状态更加可预测,所以错误使用的结果更容易被注意到。
getDerivedStateFromProps
会在调用 render
方法以前被调用,它应该返回一个用于更新状态的对象,或者若是不更新任何状态就返回 null
。
这个方法适用于一些罕见的用例,其中 state
依赖 prop
的变化。例如,能够很方便地实现一个<Transition>
组件,它会比较上一个和下一个子组件,而后决定它们中的哪一个须要进行动画渲染。
衍生 state 会致使冗长的代码,并让你的组件难以开发和维护。
你能够考虑更简单的替代方案:
componentDidUpdate
生命周期。* 若是你想在 prop 发生变动时“重置”某个状态,请考虑建立受控组件或带有键的非受控组件。
props
的纯函数和类定义以外的状态,在getDerivedStateFromProps()
和其余类方法之间重用一些代码。注意,无论怎样,这个方法都会在每次进行渲染时触发。这与 UNSAFE_componentWillReceiveProps
彻底相反。它只在父组件进行从新渲染时触发,并且不做为本地 setState
的结果。
将nextProps.someValue
与this.props.someValue进行比较。 若是二者都不一样,那么咱们执行一些操做:
static getDerivedStateFromProps(nextProps, prevState){ if(nextProps.someValue!==prevState.someValue){ return { someState: nextProps.someValue}; } return null }
它接收两个参数 nextProps
和 prevState
。如前所述,你没法在这个方法中访问 this
。你必须将 prop 存储在 state 中,而后将 nextProps
与以前的 prop 进行对比。在上面的代码中,nextProps 和 prevState 进行了比较。若是二者不一样,则返回一个用于更新状态的对象,不然就返回 null,表示不须要更新状态。若是 state 发生变动,就会调用 componentDidUpdate,咱们能够像在 componentWillReceiveProps 中那样执行所需的操做。
react v16.3,最大的变更莫过于生命周期去掉了如下三个:
同时为了弥补失去上面三个周期的不足又加了两个:
旧的生命周期十分完整,基本能够捕捉到组件更新的每个state/props/ref,没有什从逻辑上的毛病。
可是架不住官方本身搞事情,react打算在17版本推出新的Async Rendering,提出一种可被打断的生命周期,而能够被打断的阶段正是实际dom挂载以前的虚拟dom构建阶段,也就是要被去掉的三个生命周期。
生命周期一旦被打断,下次恢复的时候又会再跑一次以前的生命周期,所以componentWillMount,componentWillReceiveProps, componentWillUpdate 都不能保证只在挂载/拿到props/状态变化的时候刷新一次了,因此这三个方法被标记为不安全。
你的点赞是我持续分享好东西的动力,欢迎点赞!