react16 特性碎碎念

生命就是数据处理的过程。那么认知升级,就是某部分算法迭代和优化的过程。
—《未来简史》

V16.0

返回结构的升级
v15版本要求返回的必须都是一个html元素;
v16版本规定返回的拥有5类大全:React elements, 数组和Fragments,Portal,String/numbers,boolean/null;

Error Boundary

v15版本的容错机制不突出,一旦渲染过程出现问题,会crash掉整个页面,显示白屏;

v16版本的边界错误很优秀,也就是说边界错误用于捕获子组件树(组件在树中比他低级的组件树)的JS异常,log一个错误并展示一个回退的UI;捕获范围:渲染期内,生命周期内,整个组件树的构造函数内;
比如:单独给出的一个组件来抛出了异常,需要单独检测,如果是在其他组件内部抛错,在条件后面加上 throw new Error(‘crashed!’),组件内直接引入抛出组件就可以了,demo可以直接copy官网get;

捕获组件可以在errorInfo信息中给出组件的错误信息;
捕获盲区:

  • 不能捕获事件函数内部的错误,因为捕获范围发生在渲染阶段内,因此事件函数内部的容错可以使用trycatch来get;
  • 不能捕获异步请求中的数据,不能捕获服务端的渲染数据;
  • 不能捕获边界组件自己出现的错误;

react portals

portal的出现可以独立于页面的dom层级像组件一样使用,可以保证不在父组件之内而且是显示在独立于原来app在外的同层级组件。
在使用的时候 页面上直接引入DOM就OK了;

优化SSR

  • 生成简洁的HTML,可读性更强;
  • 宽松的客户端一致性体验:
    v15:会将SSR的结果与客户端生成的做一个个字节的对比校验 ,一点不匹配发出waring同时就替换整个SSR生成的树。v16:对比校验会更宽松一些,比如,v16允许属性顺序不一致,而且遇到不匹配的标签,还会做子树的修改,不是整个替换。
    注意点: v16不会自动fix SSR 属性跟client html属性的不同,但是仍然会报waring,所以我们需要自己手动去修改。
  • v16服务端渲染速度更快一些
    因为v15下 server client都需要生成vDOM,但是其实在服务端, 当我们的改动触及render的时候,生成的vDom就会被立即抛弃掉, 所以在server端生成vDom是没有意义的。对于生命周期来说:React16由于异步渲染等特性会让之前的一些方法如componentWillMount变得不够安全高效逐步废弃。

V16.2

Fragement
render里可以通过Fragement直接返回多个组件,该组件会自动添加key值,使用者不用担心唯一键值的问题。

V16.3

部分生命周期变更
由于异步渲染的改动,所以componentWillReceiveProps,componentWillUpdate,componentWillMount 三个生命周期可能要抛弃使用。
但是目前还是基于最小改变的基础上改变,在V17版本中,只能在前面加"UNSAFE_" 的前缀来使用。

context API
context 就是可以使用全局的变量,不需要一层层pass props下去,比如主题颜色;
什么场景下需要用context? 一些相同的data需要被大多的component用到,并且还是在不同的层级里。 一般用于主题,存储数据等。
context 是我初识react升级版本之后的缺失点,因此需要开一篇新文记录我心中的context来记录~

createRef
使用新的 React.createref() 函数使 ref 创建变得更容易:

// 在 class 中声明
third = React.createRef();
// 或者在 constructor 中声明
this.third = React.createRef();

// 在 render 函数中:
<input type="text" defaultValue="Third" ref={this.third} />;

// 获取 ref
this.third.current;

// 获取 input 的 value 
this.third.current.value;

forwardRef API
使用场景:父组件需要将自己的引用传给子组件。如果你写的是一个高阶组件,那么推荐使用forwardAPI 将ref传给下面的component。

const testRef = React.forwardRef((props,ref)=>{
  ...
})

V16.4

今天 React 16.4 发布了, getDerivedStateFromProps 的触发时机有所改动——原本在父组件重新渲染它时才会触发 getDerivedStateFromProps ,现改为只要渲染就会触发,包括自身 setState 。这一变化进一步地区分了该方法与 componentWillReceiveProps ,更适合异步渲染。

getDerivedStateFromProps

  1. 这个函数会在render函数被调用之前调用,包括第一次的初始化组件以及后续的更新过程中,每次接收新的props之后都会返回一个对象作为新的state,返回null则说明不需要更新state。
  2. 该方法主要用来替代componentWillReceiveProps方法,willReceiveProps经常被误用,导致了一些问题,因此在新版本中被标记为unsafe。willReceiveProps的常见使用方法是根据传进来的属性值判断是否要load新的数据。但这个方法的一个问题是外部组件多次频繁更新传入多次不同的 props,而该组件将这些更新 batch 后仅仅触发单次自己的更新,这种写法会导致不必要的异步请求。
  3. 那么,相比下来getDerivedStateFromProps配合componentDidUpdate的方式只在更新触发后请求数据,相比下来更节省资源。写法如下:
class ExampleComponent extends React.Component {
  state = {
    isScrollingDown: false,
    lastRow: null,
  };

  static getDerivedStateFromProps(nextProps, prevState) {
    // 不再提供 prevProps 的获取方式
    if (nextProps.currentRow !== prevState.lastRow) {
      return {
        isScrollingDown: nextProps.currentRow > prevState.lastRow,
        lastRow: nextProps.currentRow,
      };
    }

    // 默认不改动 state
    return null;
  }
  
  componentDidUpdate() {
    // 仅在更新触发后请求数据
    this.loadAsyncData()
  }

  loadAsyncData() {/* ... */}
}

注意getDerivedStateFromProps是一个static方法,意味着拿不到实例的this

getSnapshotBeforeUpate

该方法的触发时间为update发生的时候,在render之后dom渲染之前返回一个值,作为componentDidUpdate的第三个参数。该函数与 componentDidUpdate 一起使用可以取代 componentWillUpdate 的所有功能,比如以下是官方的例子:

class ScrollingList extends React.Component {
  constructor(props) {
    super(props);
    this.listRef = React.createRef();
  }

  getSnapshotBeforeUpdate(prevProps, prevState) {
    // Are we adding new items to the list?
    // Capture the scroll position so we can adjust scroll later.
    if (prevProps.list.length < this.props.list.length) {
      const list = this.listRef.current;
      return list.scrollHeight - list.scrollTop;
    }
    return null;
  }

  componentDidUpdate(prevProps, prevState, snapshot) {
    // If we have a snapshot value, we've just added new items.
    // Adjust scroll so these new items don't push the old ones out of view.
    // (snapshot here is the value returned from getSnapshotBeforeUpdate)
    if (snapshot !== null) {
      const list = this.listRef.current;
      list.scrollTop = list.scrollHeight - snapshot;
    }
  }

  render() {
    return (
      <div ref={this.listRef}>{/* ...contents... */}</div>
    );
  }
}

引用掘金例子来对以上3个关联生命周期总结:

class Example extends React.Component {
  static getDerivedStateFromProps(nextProps, prevState) {
    // 这一生命周期方法是静态的,它在组件实例化或接收到新的 props 时被触发
    // 若它的返回值是对象,则将被用于更新 state ;若是 null ,则不触发 state 的更新

    // 配合 `componentDidUpdate` 使用,这一方法可以取代 `componentWillReceiveProps`
  }

  getSnapshotBeforeUpdate(prevProps, prevState) {
    // 该方法在实际改动(比如 DOM 更新)发生前的“瞬间”被调用,返回值将作为 `componentDidUpdate` 的第三个参数

    // 配合 `componentDidUpdate` 使用,这一方法可以取代 `componentWillUpdate`
  }

  componentDidUpdate(props, state, snaptshot) {
      // 新增的参数 snapshot 即是之前调用 getSnapshotBeforeUpdate 的返回值
  }
}

……暂时先写到这里啦

对于生命周期的解释,比较好的?还有掘金
参考链接:https://mp.weixin.qq.com/s/Ldi2LOENuvF2HKoWvMFoBg

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值