Awesome Open Source
Awesome Open Source

Summary

Build Status NPM license

🔥 Suspense/Lazy for ReasonReact.

Installation

npm install reason-loadable --save

Then add "reason-loadable" in "bsconfig.json" :

"bs-dependencies": [
 "reason-loadable"
]

You can now use "ReLoadable" module.

Note : "ReLoadable" contain type definition, it doesn't add any single bit into your project.

Support

  • ReasonReact component (JSX v3). ✔️
  • Non-ReasonReact component (third-party React component or your own plain JavaScript React component). ✔️

ReasonReact JSX v2 isn't supported : Please consider migrating to JSX v3 (new ReasonReact hook components).

Example

  1. Create a ReasonReact hook component (JSX v3).
/* HelloWorld.re */
[@react.component]
let make = (~name) => <h1> (React.string("Hello world " ++ name)) </h1>;

/* Export default is necessary because React lazy function always resolve the default export. */
let default = make;
  1. Create type-safe lazy component with "ReLoadable.lazy_" and "ReLoadable.import".
/* LazyHelloWorld.re */
module type T = (module type of WithPure);

/*
  Needed for BuckleScript to not import the original component :
  See https://github.com/BuckleScript/bucklescript/issues/3543
*/
let unsafePlaceholder: module T = [%raw {|{}|}];

module UnsafePlaceholder = (val unsafePlaceholder);

let makeProps = UnsafePlaceholder.makeProps;

let make =
  ReLoadable.lazy_(() => ReLoadable.import(UnsafePlaceholder.make, "./HelloWord.bs.js"));
  1. Render lazy component anywhere in your ReasonReact app with "React.Suspense".
/* App.re */
[@react.component]
let make = () => {
  <React.Suspense fallback={<div> (React.string("Loading ...")) </div>}>
    <LazyHelloWorld name="Zeus" />
  </React.Suspense>;
};

More example are available in repository.

Non-ReasonReact component

  1. Create type-safe lazy component with "ReLoadable.lazy_" and "ReLoadable.import".
/* LazyButton.re */
/* You have to type non-ReasonReact component props explicitly. */
module type T = {
  [@react.component]
  let make: (~text: string) => React.element;
};

/*
  Needed for BuckleScript to not import the original component :
  See https://github.com/BuckleScript/bucklescript/issues/3543
*/
let unsafePlaceholder: module T = [%raw {|{}|}];

module UnsafePlaceholder = (val unsafePlaceholder);

let makeProps = UnsafePlaceholder.makeProps;

/* "@my-component-lib/button" should have a default export. */
let make =
  ReLoadable.lazy_(() => ReLoadable.import(UnsafePlaceholder.make, "@my-component-lib/button"));
  1. Render lazy component anywhere in your ReasonReact app with "React.Suspense".
/* App.re */
[@react.component]
let make = () => {
  <React.Suspense fallback={<div> (React.string("Loading ...")) </div>}>
    <LazyButton text="Click !" />
  </React.Suspense>;
};

Experimental SuspenseList

Concurrent mode is only available in the experimental builds of React. To install them, run :

npm install [email protected] [email protected]

There are no semantic versioning guarantees for the experimental builds. APIs may be added, changed, or removed with any @experimental release.

Experimental releases will have frequent breaking changes.

You can try these builds on personal projects or in a branch, but we don’t recommend running them in production.

Sometime, there's breaking change in experimental builds. For example, "createRoot" function has been changed to "unstable_createRoot" recently.

Be prepared to do some research into ReasonReact and React source code if something goes wrong, especially when binding between ReasonReact and React doesn't match due to breaking changes.

Experimental ReasonReact API is available under the "Experimental" module : https://github.com/reasonml/reason-react/blob/master/src/ReactDOMRe.re#L40

Some React experimental builds can break the SuspenseList API.

Here is one experimental build that seem to work well with SuspenseList API : 0.0.0-experimental-aae83a4b9.

npm install [email protected] [email protected]
/* App.re */
/* LazyButton and LazyHelloWorld are lazy components (see previous examples). */
[@react.component]
let make = () => {
  <React.SuspenseList>
    <React.Suspense fallback={<div> (React.string("Loading ...")) </div>}>
      <LazyButton text="Click !" />
    </React.Suspense>
    <React.Suspense fallback={<div> (React.string("Loading ...")) </div>}>
      <LazyHelloWorld name="Zeus" />
    </React.Suspense>
  </React.SuspenseList>;
};
/* index.re */
/* You have to use the experimental createRoot API explicitly. */
let _ =
  switch (ReactDOMRe.Experimental.createRootWithId("root")) {
  | Ok(root) => ReactDOMRe.Experimental.render(root, <App />)
  | Error(err) => Js.log(err)
  };

API

ReLoadable.import: (Js.t('a) => React.element), string) => Js.Promise.t(Js.t('a) => React.element)

Dynamic import React component.

ReLoadable.lazy_: (unit => Js.Promise.t('a)) => 'a

React.lazy binding.

Special thanks to


Get A Weekly Email With Trending Projects For These Topics
No Spam. Unsubscribe easily at any time.
javascript (68,779
component (552
dynamic (116
reasonml (103
import (52
bucklescript (43
code-splitting (43
lazy (26
suspense (17

Find Open Source By Browsing 7,000 Topics Across 59 Categories