👨‍🔬 I tried experimental React and... 💥💥💥

potouridisio

Ioannis Potouridis

Posted on November 3, 2019

👨‍🔬 I tried experimental React and... 💥💥💥

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 first.

Introduction

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

These components usually look like this:

// 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.

npm i react@experimental react-dom@experimental

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

//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.

// 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.

// 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.

// 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.

// 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...

// 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.

Simple React Engineer


  1. There aren't any implementations to integrate with Suspense yet (except Relay I think). We have to copy paste from here 😂 write our own function at the moment. 

💖 💪 🙅 🚩
potouridisio
Ioannis Potouridis

Posted on November 3, 2019

Join Our Newsletter. No Spam, Only the good stuff.

Sign up to receive the latest update from our blog.

Related