为何 React16 对开发人员来说是一种福音

就像人们对更新挪动应用顺序和操纵系统觉得高兴一样,开辟人员也应当对更新框架觉得高兴。差别框架的新版本具有新特征和开箱即用的技能。

下面是将现有应用顺序从 React 15 迁移到 React 16 时应当斟酌的一些好特征。

想浏览更多优良文章请猛戳GitHub博客,一年百来篇优良文章等着你!

缺点处置惩罚

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:hiddenz-index 款式时,你愿望子组件在视觉上可以“打破”它的容器。比方,对话框、悬停卡和东西提醒。

点击检察在线事例

自定义 DOM 属性

《为何 React16 对开发人员来说是一种福音》

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 参数将即是树中近来的 Providervalue。假如没有婚配的 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
}

它吸收两个参数 nextPropsprevState。如前所述,你没法在这个要领中接见 this。你必须将 prop 存储在 state 中,然后将 nextProps 与之前的 prop 举行对照。在上面的代码中,nextProps 和 prevState 举行了比较。假如二者差别,则返回一个用于更新状况的对象,不然就返回 null,示意不须要更新状况。假如 state 发作更改,就会挪用 componentDidUpdate,我们可以像在 componentWillReceiveProps 中那样实行所需的操纵。

React 性命周期事宜

《为何 React16 对开发人员来说是一种福音》

react v16.3,最大的更改莫过于性命周期去掉了以下三个:

  • componentWillMount
  • componentWillReceiveProps
  • componentWillUpdate

同时为了填补落空上面三个周期的不足又加了两个:

  • static getDerivedStateFromProps
  • getSnapshotBeforeUpdate

为何要改

旧的性命周期非常完全,基础可以捕捉到组件更新的每一个state/props/ref,没有什从逻辑上的缺点。

然则架不住官方本身搞事变,react打算在17版本推出新的Async Rendering,提出一种可被打断的性命周期,而可以被打断的阶段恰是现实dom挂载之前的假造dom构建阶段,也就是要被去掉的三个性命周期。

性命周期一旦被打断,下次恢复的时刻又会再跑一次之前的性命周期,因而componentWillMount,componentWillReceiveProps, componentWillUpdate 都不能保证只在挂载/拿到props/状况变化的时刻革新一次了,所以这三个要领被标记为不平安。

你的点赞是我延续分享好东西的动力,迎接点赞!

迎接到场前端人人庭,内里会常常分享一些手艺资本。

《为何 React16 对开发人员来说是一种福音》

    原文作者:前端小智
    原文地址: https://segmentfault.com/a/1190000019119807
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞