👨‍🔬 I tried experimental React and... 💥💥💥
Tags: javascript, react
Published: 2019-11-03 14:11:31

Hey! 👋

I hope everyone is doing great!

I finally found some time to play with the new experimental React features and especially with Suspense for Data Fetching.

If you are interested in how things work I suggest that you read [this](https://reactjs.org/docs/concurrent-mode-intro.html) first.

### Introduction

We all have components that make asynchronous API calls in order to fetch data.

These components usually look like this:

```jsx
// UserList.js

import React, { useEffect, useState } from "react";

import { fetchUsers } from "./userApi";

function UserList() {
  const [users, setUsers] = useState(null);

  useEffect(() => {
    fetchUsers().then(setUsers);
  }, []);

  if (!users) {
    return <div>Loading...</div>;
  }

  return (
    <ul>
      {/*  */}
    </ul>
  );
}

```

`UserList` component will render out Loading... and fetch the users **after** that.

React's new features will help us achieve two things.

1. Avoid writing boilerplate logic for the UI when our data are not ready
2. Fetch as soon as possible

### Installation

In order to experiment with the new features you need to have experimental `react` and `react-dom` installed in your project.

```sh
npm i react@experimental react-dom@experimental
```

The very next thing you need to do is make the following changes to your `index.js`.

```jsx
//index.js

import React from "react";
// import { render } from "react-dom";
import { createRoot } from "react-dom";

import App from "./App.js";

// render(<App />, document.getElementById("root");
createRoot(document.getElementById("root")).render(<App />);
```

### Example

We need two things to start with:

1. The `Suspense` component from React to wrap our component.
2. A function [^1] that will tell our data's state to that `Suspense` component.

Imagine that this function looks like this.

```javascript
// helpers.js

export function wrapPromise(promise) {
  // There's no actual magic in it 🧙‍♂️
}
```

I'm not proud of this part but... here's how I used it.

```javascript
// userApi.js

import { wrapPromise } from "./helpers";

export function fetchUsers() {
  // I intentionally used https://reqres.in for that delay
  const input = "https://reqres.in/api/users?delay=1";

  return wrapPromise(fetch(input).then(value => value.json()));
}
```

Then I used this component in order to render each user.

```jsx
// UserListItem.js

import React from "react";

function UserListItem({ email, first_name, id, last_name }) {
  return (
    <li key={id}>
      <span>
        {first_name} {last_name}
      </span>
      <p>{email}</p>
    </li>
  );
}

export default UserListItem;
```

Then I simply wrapped my component that contains the data with `Suspense`.

```jsx
// App.js
import React, { Suspense } from "react"; 

import UserList from "./UserList";

function App() {
  return (
    <Suspense fallback={<div>Loading...</div>}>
      <UserList />
    </Suspense>
  );
}

export default App;
```

And finally...

```jsx
// UserList.js

import React from "react";

import { fetchUsers } from "./userApi";
import UserListItem from "./UserListItem";

const resource = fetchUsers();

function UserList() {
  const { data: users } = resource.read();

  return <ul>{users.map(UserListItem)}</ul>;
}

export default UserList;
```

### Conclusion

My conclusion is that we went from a component that was:

1. responsible for fetching the data
2. fetching the data after rendering
3. handling the UI while the data wasn't ready
4. rendering the data when they were ready

to a component that is:

1. rendering the data

You can find the complete example [here](https://codesandbox.io/s/hungry-sanderson-y1hzo).

![Simple React Engineer](https://res.cloudinary.com/dnwzefzmd/image/upload/v1572789959/simple-man_icnas0.jpg)

[^1]: There aren't any implementations to integrate with `Suspense` yet (except Relay I think). We have to ~~copy paste from [here](https://codesandbox.io/s/frosty-hermann-bztrp?fontsize=14&module=%2Fsrc%2FfakeApi.js)~~ 😂 write our own function at the moment.