👨🔬 I tried experimental React and... 💥💥💥
Ioannis Potouridis
Posted on November 3, 2019
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.
- Avoid writing boilerplate logic for the UI when our data are not ready
- 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:
- The
Suspense
component from React to wrap our component. - 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:
- responsible for fetching the data
- fetching the data after rendering
- handling the UI while the data wasn't ready
- rendering the data when they were ready
to a component that is:
- rendering the data
You can find the complete example here.
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
November 28, 2024