侯体宗的博客
  • 首页
  • Hyperf版
  • beego仿版
  • 人生(杂谈)
  • 技术
  • 关于我
  • 更多分类
    • 文件下载
    • 文字修仙
    • 中国象棋ai
    • 群聊
    • 九宫格抽奖
    • 拼图
    • 消消乐
    • 相册

为什么说React 16是开发者的福音?

前端  /  管理员 发布于 6年前   345

就像人们对更新移动应用程序和操作系统感到兴奋一样,开发人员也应该对更新框架感到兴奋。不同框架的新版本具有新特性和开箱即用的技巧。

下面是将现有应用程序从 react 15 迁移到 react 16 时应该考虑的一些好特性。


错误处理

React 16 引入了错误边界的新概念。

现在在React 16中,大家就能使用错误边界功能,而不用一发生错误就解除整个程序挂载了。把错误边界看成是一种类似于编程中try-catch语句的机制,只不过是由 React 组件来实现的。

错误边界是一种React组件。它及其子组件形成一个树型结构,能捕获JavaScript中所有位置的错误,记录下错误,并且还能显示一个后备界面,避免让用户直接看到组件树的崩溃信息。

这里涉及到一种新的生命周期函数叫componentDidCatch(error, info)。无论什么样的类组件,只要定义了这个函数,就成为了一个错误边界。

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程序挂载也不会被解除。只有出错的那个组件会显示一个后备界面,而整个程序仍然完全正常运行。点击查看在线事例

关于错误边界更多的内容可查看官网。


新的 render 返回类型:片段和字符串

现在,在渲染时可以摆脱将组件包装在 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

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 样式时,你希望子组件在视觉上能够“突破”它的容器。例如,对话框、悬停卡和工具提示。点击查看在线事例


自定义 DOM 属性


React15 会忽略任何未知的 DOM 属性。React 会跳过它们,因为无法识别它们。

// 你的代码<div mycustomattribute="something" />

React 15 将渲染一个空的 div:

// React 15 output:<div />

在 React16 中,输出将如下所示(会显示自定义属性,并且完全不会被忽略)

// React 16 output:<div mycustomattribute="something" />


在 state 中设置 null 避免重新渲染

有时候我们需要通过函数来判断组件状态更新是否触发重新渲染,在 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);

更多相关信息请阅读这里


创建 ref

现在使用 React16 创建refs要容易得多。 为什么需要使用refs:

管理焦点、文本选择或媒体播放。触发动画。与第三方 DOM 库集成。

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指向的方法, 在Ref 所指向的组件,在render后就可以调用,React16.3 中提供了current 属性,用于引用render后的节点:

componentDidMount(){  console.log(this.myRef.current);  //render之后就可以输出该ref指向的那个节点}

此外,同样的 Ref 所指向的节点可以是 dom 节点,也可以是类组件。

Ref 的值因节点的类型不同而有所不同:

当 ref 属性用于 html 元素时,在构造函数中使用 React.createRef() 创建的 ref 将底层 DOM 元素作为 current 属性。当 ref 属性用于自定义类组件时,ref 对象将已挂载的组件实例作为 current 属性。你可能不会在功能组件上使用 ref 属性,因为它们没有实例。


Context API

Context 提供了一种通过组件树传递数据的方法,无需在每一层手动传递 prop。

React.createContext
const { Provider, Consumer } = React.createContext(defaultValue)

创建{Provider,Consumer}对。当 React 渲染 Consumer 时,它将从树中最接近的 Provider 读取当前上下文值。

defaultValue 参数只在消费者在树中找不到匹配的 Provider 时才会用到,这在单独测试组件时十分有用。注意:将 undefined 作为 Provider 值传递进去并不会导致 Consumer 使用 defaultValue。

Provider
<Provider value={/* some value */}>

一个允许 Consumer 订阅上下文变更的 React 组件。

一个 Provider 可以连接多个 Consumer,可以在树中嵌套 Provider,实现更深的值覆盖。

Consumer
<Consumer>  {value => /* render something based on the context value */}</Consumer>

订阅上下文更改的 React 组件。

需要一个函数作为子组件。这个函数接收当前上下文值,并返回一个 React 节点。传给函数的 value 参数将等于树中最近的 Provider 的 value。如果没有匹配的 Provider,则 value 参数将等于传给 createContext() 的 defaultValue。

static getDerivedStateFromProps()

在很长一段时间内,componentWillReceiveProps是在没有附加渲染的情况下更新状态的唯一方法。

在版本16.3中,我们引入了一个全新的生命周期函数getDerivedStateFromProps用来替换componentWillReceiveProps,并用更安全的方式处理相同的场景。

与此同时,我们意识到人们对如何使用这两种方法有很多误解,我们发现了一些反模式,这些错误导致了微妙而令人困惑的bug。

在16.4中,有关getDerivedStateFromProps的修复使得派生状态更加可预测,因此错误使用的结果更容易被注意到。

getDerivedStateFromProps 会在调用 render 方法之前被调用,它应该返回一个用于更新状态的对象,或者如果不更新任何状态就返回 null。

这个方法适用于一些罕见的用例,其中 state 依赖 prop 的变化。例如,可以很方便地实现一个<Transition> 组件,它会比较上一个和下一个子组件,然后决定它们中的哪个需要进行动画渲染。

衍生 state 会导致冗长的代码,并让你的组件难以开发和维护。

你可以考虑更简单的替代方案:

如果你需要在 prop 发生变更时做一些其他事情(例如数据提取或动画),请改用 componentDidUpdate 生命周期。如果你只想在 prop 发生变更时重新计算某些数据,请改用 memoization helper:

* 如果你想在 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 生命周期事件


react v16.3,最大的变动莫过于生命周期去掉了以下三个:

componentWillMountcomponentWillReceivePropscomponentWillUpdate

同时为了弥补失去上面三个周期的不足又加了两个:

static getDerivedStateFromPropsgetSnapshotBeforeUpdate为什么要改

旧的生命周期十分完整,基本可以捕捉到组件更新的每一个state/props/ref,没有什从逻辑上的毛病。

但是架不住官方自己搞事情,react打算在17版本推出新的Async Rendering,提出一种可被打断的生命周期,而可以被打断的阶段正是实际dom挂载之前的虚拟dom构建阶段,也就是要被去掉的三个生命周期。

生命周期一旦被打断,下次恢复的时候又会再跑一次之前的生命周期,因此componentWillMount,componentWillReceiveProps, componentWillUpdate 都不能保证只在挂载/拿到props/状态变化的时候刷新一次了,所以这三个方法被标记为不安全。


翻译来自:https://medium.com/m/global-identity?redirectUrl=https%3A%2F%2Fmedium.freecodecamp.org%2Fwhy-react16-is-a-blessing-to-react-developers-31433bfc210a



  • 上一条:
    在Vue2与Vue3中构建相同的组件
    下一条:
    事件循环以及vue.nextTick的应用
  • 昵称:

    邮箱:

    0条评论 (评论内容有缓存机制,请悉知!)
    最新最热
    • 分类目录
    • 人生(杂谈)
    • 技术
    • linux
    • Java
    • php
    • 框架(架构)
    • 前端
    • ThinkPHP
    • 数据库
    • 微信(小程序)
    • Laravel
    • Redis
    • Docker
    • Go
    • swoole
    • Windows
    • Python
    • 苹果(mac/ios)
    • 相关文章
    • 使用 Alpine.js 排序插件对元素进行排序(0个评论)
    • 在js中使用jszip + file-saver实现批量下载OSS文件功能示例(0个评论)
    • 在vue中实现父页面按钮显示子组件中的el-dialog效果(0个评论)
    • 使用mock-server实现模拟接口对接流程步骤(0个评论)
    • vue项目打包程序实现把项目打包成一个exe可执行程序(0个评论)
    • 近期文章
    • 智能合约Solidity学习CryptoZombie第三课:组建僵尸军队(高级Solidity理论)(0个评论)
    • 智能合约Solidity学习CryptoZombie第二课:让你的僵尸猎食(0个评论)
    • 智能合约Solidity学习CryptoZombie第一课:生成一只你的僵尸(0个评论)
    • 在go中实现一个常用的先进先出的缓存淘汰算法示例代码(0个评论)
    • 在go+gin中使用"github.com/skip2/go-qrcode"实现url转二维码功能(0个评论)
    • 在go语言中使用api.geonames.org接口实现根据国际邮政编码获取地址信息功能(1个评论)
    • 在go语言中使用github.com/signintech/gopdf实现生成pdf分页文件功能(0个评论)
    • gmail发邮件报错:534 5.7.9 Application-specific password required...解决方案(0个评论)
    • 欧盟关于强迫劳动的规定的官方举报渠道及官方举报网站(0个评论)
    • 在go语言中使用github.com/signintech/gopdf实现生成pdf文件功能(0个评论)
    • 近期评论
    • 122 在

      学历:一种延缓就业设计,生活需求下的权衡之选中评论 工作几年后,报名考研了,到现在还没认真学习备考,迷茫中。作为一名北漂互联网打工人..
    • 123 在

      Clash for Windows作者删库跑路了,github已404中评论 按理说只要你在国内,所有的流量进出都在监控范围内,不管你怎么隐藏也没用,想搞你分..
    • 原梓番博客 在

      在Laravel框架中使用模型Model分表最简单的方法中评论 好久好久都没看友情链接申请了,今天刚看,已经添加。..
    • 博主 在

      佛跳墙vpn软件不会用?上不了网?佛跳墙vpn常见问题以及解决办法中评论 @1111老铁这个不行了,可以看看近期评论的其他文章..
    • 1111 在

      佛跳墙vpn软件不会用?上不了网?佛跳墙vpn常见问题以及解决办法中评论 网站不能打开,博主百忙中能否发个APP下载链接,佛跳墙或极光..
    • 2016-10
    • 2016-11
    • 2017-06
    • 2017-07
    • 2017-08
    • 2017-09
    • 2017-10
    • 2017-11
    • 2018-03
    • 2018-04
    • 2018-05
    • 2018-06
    • 2018-09
    • 2018-11
    • 2018-12
    • 2019-02
    • 2020-03
    • 2020-04
    • 2020-05
    • 2020-06
    • 2021-04
    • 2021-05
    • 2021-07
    • 2021-08
    • 2021-09
    • 2021-10
    • 2021-11
    • 2022-08
    • 2022-09
    • 2022-10
    • 2022-11
    • 2022-12
    • 2023-01
    • 2023-02
    • 2023-03
    • 2023-04
    • 2023-05
    • 2023-06
    • 2023-07
    • 2023-09
    • 2023-10
    • 2023-11
    • 2023-12
    • 2024-01
    • 2024-02
    • 2024-03
    • 2024-04
    Top

    Copyright·© 2019 侯体宗版权所有· 粤ICP备20027696号 PHP交流群

    侯体宗的博客