React Suspense 尝鲜

栏目: IOS · Android · 发布时间: 6年前

内容简介:如同字面意思,Suspense 让组件遇到异步操作时进入“悬停”状态,等异步操作有结果时再回归正常状态。异步操作简单归为两类:异步加载代码就是所谓的

如同字面意思,Suspense 让组件遇到异步操作时进入“悬停”状态,等异步操作有结果时再回归正常状态。

异步操作简单归为两类:

  1. 异步加载代码
  2. 异步加载数据

异步加载代码

异步加载代码就是所谓的 code splitting ,实现起来就像是这样:

import React, {lazy, Suspense} from 'react';

const OtherComponent = lazy(() => import('./OtherComponent'));

function MyComponent() {
  return (
    <Suspense fallback={<div>Loading...</div>}>
      <OtherComponent />
    </Suspense>
  );
}
复制代码

值得一提的是目前版本 (截止至 react@16.8) 还不支持服务端渲染,但还是会在以后的版本上支持的。

异步加载数据

Suspense 异步加载数据截止到目前都是不稳定的版本,根据React 16.x Roadmap,大概到2019年中期发布稳定版本,但是 React 官方提供了一个独立的包 react-cache ,使用它结合 react@16.6.0 可以让我们提前感受一下 Suspense 异步加载数据。

import { unstable_createResource } from 'react-cache';

const getSomething = (something) => new Promise((resolve) => {
  setTimeout(() => {
    resolve(something);
  }, 1000);
})

const resource = unstable_createResource((id) => getSomething(id))

function Demo() {
  const data = resource.read(666)
  return (
    <div>{data}</div>
  );
}
复制代码

细谈 Suspense

在上面的实例中,Suspense 组件传入了 fallback 属性,这个属性用于显示加载中的页面,就是俗称的 loading 咯。

那么我们在想一个问题,如果一个异步请求数据的过程非常快,这样会使得加载中画面一闪而过,导致闪屏。

Suspense 针对这种情况给出解决方案 maxDuration 属性:

<Suspense fallback={<Spinner />} maxDuration={500}>
  // ...
</Suspense>
复制代码

当异步获取数据的时间大于 maxDuration 时间时展示 fallback ,否则直接展示数据。

需要注意的是 maxDuration 属性只有在 Concurrent Mode 下才能生效,在以往的 Sync 模式下 maxDuration 始终为0, 具体使用简单给出一个实例:

// ReactDOM.render(<App />, document.getElementById('root'));
ReactDOM
  .unstable_createRoot(document.getElementById('root'))
  .render(
    <React.unstable_ConcurrentMode>
      <App />
    </React.unstable_ConcurrentMode>
  );
复制代码

原理

Suspense 的实现原理颇有争议。

当我们在 render 内写异步请求数据时会抛出一个异常,当然它应该是一个 promise ,这个异常会被 Suspense 内一个新的生命周期 ComponentDidCatch 捕获到,在这个生命周期内 Suspense 将子组件渲染为 loading ,等到异步请求结束,loading结束,此时又回到了正常的组件。

翻了一下 unstable_createResource 的源码,果然 Pending 状态下会 throw 一个 suspender 对象,这个对象就是一个 promise

function unstable_createResource(fetch, maybeHashInput) {
  // ...
  var resource = {
    read: function (input) {
      // ...
      var key = hashInput(input);
      var result = accessResult(resource, fetch, input, key);
      switch (result.status) {
        case Pending:
          {
            var suspender = result.value;
            throw suspender;
          }
        case Resolved:
          {
            var _value = result.value;
            return _value;
          }
        case Rejected:
          {
            var error = result.value;
            throw error;
          }
        default:
          // Should be unreachable
          return undefined;
      }
    },
    // ...
  };
  return resource;
}
复制代码

以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

Ruby on Rails Tutorial

Ruby on Rails Tutorial

Michael Hartl / Addison-Wesley Professional / 2012-8-6 / USD 44.99

"Ruby on Rails(TM) Tutorial by Michael Hartl has become a must-read for developers learning how to build Rails apps." -Peter Cooper, Editor of Ruby Inside Using Rails, developers can build web applica......一起来看看 《Ruby on Rails Tutorial》 这本书的介绍吧!

SHA 加密
SHA 加密

SHA 加密工具

XML、JSON 在线转换
XML、JSON 在线转换

在线XML、JSON转换工具

Markdown 在线编辑器
Markdown 在线编辑器

Markdown 在线编辑器