专栏首页前端探索使用 React.Suspense 替换 react-loadable

使用 React.Suspense 替换 react-loadable

当前大部分 React 应用需要使用 code splitting 的时候,都选择使用优秀的 react-loadable 来处理检测代码段是否已加载。然而,随着React v16.6 的发布,我们有一个非常难得的机会 ,可以删除我们的第三方依赖!

React.Suspense是一个新添加到核心React库中的功能,t他的功能基本和 react-loadable 一致,所以不用多说,让我们来看看用 React.Suspense 替换 react-loadable。

首先是 code splitting(代码分割)

如果你不太熟悉这个功能,webpack 基本上可以帮助你把代码打包成多个chunk,当用户打开你的应用的时候,先会下载一个主bundle,然后当用户导航到一些页面包含了其他的逻辑和静态资源的使用,再按需加载这些chunk。但是要手动处理成这个效果非常的复杂,当然这样处理后可以很有效地减少用户的白屏时间,并且让移动端用户有更好的体验。webpack(或者其他解决方案)在这里扮演了一个很重要的角色,他可以在创建这些bundle的时候处理这些复杂的逻辑,并且在需要的时候再去下载他们。所以我们所需要做的就是将该功能合并到我们的应用程序中,这样用户就可以获得无缝的体验。

Step 1: 升级到 React 16.6

对于 v16 的用户来说,可以直接升级到 16.6,但是对于v15的用户来说,请按照官方迁移说明来升级。

Step 2: 确定您的异步组件

在 react-loadable 当中,按需加载可能在长这样:

const Loading = ({ pastDelay }) => {
  if (pastDelay) {
    return <Spinner />;
  }
  return null;
};
 
export const johanAsyncComponent = Loadable({
  loader: () => import(/* webpackChunkName: "johanComponent" */ './johan.component'),
  loading: Loading,
  delay: 200
});

在上面的代码中,我们做了几个事情:

  1. 我们定义一个 Loading 组件,用于在请求组件的时间和加载组件以及准备渲染之间显示。
  2. johanAsyncComponent 中的loading参数是在请求/响应周期中显示的组件,这里我们定义了一个 自定义Loading组件
  3. 设置了一个delay,我们只在加载超过 200 毫秒的时候显示Spinner ,这样做可以很好地避免在请求快速完成时“闪烁”加载中的组件。

Step 3:转换到 React.Suspense

使用 React.Suspense 显然代码更为优雅。

const johanComponent = React.lazy(() => import(/* webpackChunkName: "johanComponent" */ './myAwesome.component'));
 
export const johanAsyncComponent = props => (
  <React.Suspense fallback={<Spinner />}>
    <johanComponent {...props} />
  </React.Suspense>
);
  1. 我们使用React.lazy封装动态import,类似于第一个示例中的'loading'参数。
  2. 我们定义一个React.Suspense组件,其中包含一组fallback JSX,以便在我们等待异步加载时进行渲染。 通常,这将是一个微调器或其他等待指示器。
  3. 我们定义了一些 children 的 JSX,这些都是使用 React.lazy 包含的组件。

ok, 到此,其实我们已经实现了和 react-loadable 一样的功能。或许细心的你可能发现了,React.Suspense 没有 delay 参数。是的, React.Suspense 没有在内置支持 delay 功能,因此,即使加载工程只需要几毫秒的时间, fallback也会被执行,就上述代码来说,也就是 Spinner 会闪烁一下,如果资源被加载得非常快得话。就目前而言,我们需要自己在 fallback 得组件中自行处理这些逻辑,例如在 componentDidMount 中设置一个定时器,使其直到将来的某个时间才呈现。

Step 4:加载出错的处理

该如何处理如果出现chunk加载失败的情况呢?

react-loadable

优秀的库当然有内置的方法支持处理加载失败的情况

const Loading = (props) => {
  if (props.error) {
    return <p>Error!</p>;
  } else if (props.pastDelay) {
    return <p>Loading...</p>;
  } else {
    return null;
  }
}

Suspense

在 React 16 当中有一个新的功能Error Boundary,这只是一个可感知错误的组件,它能够从其children中捕获和处理错误。为了处理异步加载的问题,我们可以简单地定义一个自定义的ErrorEdge组件,并将异步组件的使用包装在其中。

<MyCustomErrorBoundary>
  <MyAwesomeAsyncComponent />
</MyCustomErrorBoundary>

最后一步

npm uninstall react-loadable

替换有什么好处?

显然,当我们考虑升级或重构时,我们总是用“它以目前的方式工作得很好”为借口推脱。那么,这是否值得升级?

更小的bundle: react-loadable gzip后大概是 2K,去掉这个第三方库后,所以打包时间并没有减少多少,但是确确实实减少了2K。

增加可维护性:使用 React 的核心库,总比第三方库更容易维护。

总结

总的来说,我不敢说这是一个必须替换的功能,但是考虑到众多的因素,他们两个的功能基本是相同的,而且代码修改也相对比较简单,并不需要做很大的改动,所以建议使用这个新特性来做按需加载。

原文链接:https://objectpartners.com/2018/12/05/migrate-from-react-loadable-to-react-suspense/

原文作者:Mike Plummer

我来说两句

0 条评论
登录 后参与评论

相关文章

  • 【React总结(一)】浅谈 React 中 key

    上周在处理项目的时候,由于之前项目中引用的是 cdn 中的生产环境的 React 所以导致所有在开发环境中应该暴露的 warnning 都被屏蔽了,上周修改了 ...

    志航
  • 【React总结(二)】使用 Render props 复用代码

    有一天产品产品经理突然找过来和你说,他并不想把这个打印在,控制台,而是像通过弹窗的形式 alert 出来,让用户看见,那么你会怎么做?

    志航
  • 理解 React Hooks

    Sophie Alpert 和 Dan Abramov 在 React Conf 2018 中 提出了 hooks 这个概念,让我们一起来看看 Hooks 在解...

    志航
  • 【JVM】浅谈双亲委派和破坏双亲委派

    笔者曾经阅读过周志明的《深入理解Java虚拟机》这本书,阅读完后自以为对jvm有了一定的了解,然而当真正碰到问题的时候,才发现自己读的有多粗糙,也体会到只有实践...

    joemsu
  • 2017年高频率的互联网校园招聘面试题

    参加了2017年校招,面试了阿里、百度、腾讯、滴滴、美团、网易、去哪儿等公司,个人是客户端 Android 方向,总结了面试过程中频率出现较高的题目,希望对大家...

    哲洛不闹
  • 「React 基础」React 16 中的这几个新特性值得你关注

    本系列的上篇文章里,「React 基础」在 React 项目中使用 ES6,你需要了解这些 ,我给大家介绍了 ES6 在 React 的常见用法,本篇文章将会大...

    前端达人
  • React性能测量和分析

    上一篇文章讲了 React 性能优化的一些方向和手段,这篇文章再补充说一下如何进行性能测量和分析, 介绍 React 性能分析的一些工具和方法.

    _sx_
  • 做好 Loading 设计

    在前端产品中,我们无法保证用户的网络情况,也很难去从最末端节点优化自有网络部署。 这些或多或少地都会反映到用户端的加载延迟。

    Fred Liang
  • abp vnext2.0核心组件之模块加载组件源码解析

    abp vnext是abp官方在abp的基础之上构建的微服务框架,说实话,看完核心组件源码的时候,很兴奋,整个框架将组件化的细想运用的很好,真的超级解耦.老版整...

    郑小超.
  • box布局

    <!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title></title> <style>...

    前朝楚水

扫码关注云+社区

领取腾讯云代金券