0.2.1-alpha.0 • Published 3 years ago

@traveloka/react-load v0.2.1-alpha.0

Weekly downloads
231
License
MIT
Repository
github
Last release
3 years ago

React Load

NPM Version CircleCI PRs Welcome

Remove boilerplate handling loading, error, and result state of Promise!


Table of contents


How to use

Setup

using npm:

npm install @traveloka/react-load --save

using yarn:

yarn add @traveloka/react-load

Motivation

“The best products don’t focus on features, they focus on clarity.” — Jon Bolt

Providing loading state, error, and result callback of a Javascript Promise is common in any application.

In ES6, there's a Promise that do some async function. Lot of duplicate code being used to get the state before the async function executed, and state of Promise error / Promise success state when async function is done.

This library will give a property state before and after execution of async function.

Hooks

useLoad()

const {
  isLoading: boolean,
  isError: boolean,
  error: Error | null,
  retry: () => void,
  result: T | null,
  trigger: (...args: any[]) => Promise<T>
} = useLoad<T>((...args: any[]) => Promise<T>)

Example

import React, { useEffect } from 'react';
import { useLoad } from '@traveloka/react-load';

export default function UserListPage(props) {
  const { isLoading, isError, error, retry, result, trigger } = useLoad(fetchUserList);
  useEffect(() => {
    trigger(); // call the fetchUserList that wrapped with load attributes
  }, []); // only trigger componentDidMount
  if (isLoading) return <LoadingPage />
  if (isError) return <ErrorPage error={error} retry={retry} />
  return (
    ....
  );
}

Example

Hooks

Example 1

HOC

Example 1

Example 2

  • With decorator
import React from 'react';
import { load } from '@traveloka/react-load';

@load()
export default class UserListPage extends React.Component {
  @load()
  componentDidMount() {
    return fetchUserList(); // Note: must return a Promise
  }

  render() {
    const { load: { isLoading, isError, error, retry, result} } = this.props;
    if (isLoading) return <LoadingPage />
    if (isError) return <ErrorPage error={error} retry={retry} />
    return (
      ....
    );
  }
}
  • Without decorator
import React from 'react';
import { load, decorate } from '@traveloka/react-load';

class UserListPage extends React.Component {
  componentDidMount() {
    return fetchUserList();
  }

  render() {
    const { load: { isLoading, isError, error, retry, result} } = this.props;
    if (isLoading) return <LoadingPage />
    if (isError) return <ErrorPage error={error} retry={retry} />
    return (
      ....
    );
  }
}

decorate(UserListPage, {
  componentDidMount: load(),
});

export default load()(UserListPage);

Documentations

Given Props

PropertyTypeDefault ValueDescription
load.isLoadingbooleanfalse
load.isErrorbooleanfalse
load.errorExceptionnull
load.resultanynull
load.retryfunction() => {}

How to (not) use decorators

Using ES.next decorators is optional. This section explains how to use them, or how to avoid them.

Advantages of using decorators:

  • Minimizes boilerplate, declarative.
  • Easy to use and read. A majority of the MobX users use them.

Disadvantages of using decorators:

  • Stage-2 ES.next feature
  • Requires a little setup and transpilation, only supported with Babel / Typescript transpilation so far

You can approach using decorators in two ways:

  • Enable the currently experimental decorator syntax in your compiler (read on)
  • Don't enable decorator syntax, but leverage the built-in utility decorate to apply decorators to your classes / objects.

Using decorator syntax:

import * as React from 'react';
import { load } from '@traveloka/react-load';

@load()
class Timer extends React.Component {
  @load()
  componentDidMount() {
    /* ... */
  }

  render() {
    const { load: { isLoading, isError, error, retry, result} } = this.props;
    /* ... */
  }
}

Using the decorate utility:

import compose from 'lodash/fp/compose';
import { load, decorate } from '@traveloka/react-load';

class Timer extends React.Component {
  componentDidMount() {
    /* ... */
  }

  render() {
    /* ... */
  }
}

// decorate method
decorate(Timer, {
  componentDidMount: load(),
});

export default load()(Timer);

Babel: manually enabling decorators

To enable support for decorators, follow the following steps. Install support for decorators: npm i --save-dev babel-plugin-transform-decorators-legacy. And enable it in your .babelrc file:

{
  "presets": [
    "es2015",
    "stage-1"
  ],
  "plugins": ["transform-decorators-legacy"]
}

Note that the order of plugins is important: transform-decorators-legacy should be listed first. Having issues with the babel setup? Check this issue first.

For babel 7, see issue 1352 for an example setup.

Credits

Written by Jacky Wijaya (@jekiwijaya) at Traveloka.

0.2.1-alpha.0

3 years ago

0.2.0

5 years ago

0.1.7

5 years ago

0.1.6

5 years ago

0.1.5

5 years ago

0.1.4

5 years ago

0.1.3

5 years ago

0.1.2

5 years ago

0.1.1

5 years ago