Ever since the React team released their 16.x vision, it has definitely caught the community by storm. Some of the coolest additions to the collection are Hooks, lazy loading, Suspense, and the cache API.
This won’t be just another article on how to write Hooks, but rather what to expect in the future of React! If you have never heard of Hooks, or any other new API in React, this article will be a great start to get you excited about the future.
As we dive deeper in the article, we will cover two new concepts, which are expected to be released in Q2 2019:
I am already excited! But let’s slow down and do a quick recap before we dive deeper.
With React 16.8, Hooks are officially a part of the stable release. Some of the problems it has solved, on a high level:
componentDidMount
, componentDidUpdate
, etc., which required us to write repetitive codeIf you want to know more in detail, check here.
So, let’s check out a demo of React Hooks and how a typical app might look!
The name really gives away its intent! We need it when we want to lazily load components:
const TodoList = React.lazy(() => import("./containers/todoList"));
With the help of dynamic import using webpack, we could do it; it helps create bundles, which improves our page load speed. Let’s have fun with a demo! Just go back up to the Codesandbox demo link and change the imports to the following below:
const TodoList = React.lazy(() => import("./containers/todoList")); const CompletedList = React.lazy(() => import("./containers/completedList")); const AddNewTask = React.lazy(() => import("./containers/addNewTask"));
Notice in the below image how separate bundles are created 😄
Suspense is fairly simple to use. Let’s better understand this with the help of a code demo:
// https://codesandbox.io/s/new-6m2gj import React, { useState, useEffect, Suspense } from "react"; import ReactDOM from "react-dom"; import todoListData from "./containers/todoList/todolistData"; import Header from "./containers/header"; import Clock from "./components/Clock"; import "./styles.css"; const TodoList = React.lazy(() => import("./containers/todoList")); const CompletedList = React.lazy(() => import("./containers/completedList")); const AddNewTask = React.lazy(() => import("./containers/addNewTask")); function App() { const { todolist } = todoListData; const [todoListPayload, setTodoListPayload] = useState(todolist); const [completedTodoList, setCompletedTodoList] = useState([]); const addTodoTaskHandler = value => { // addTodoTaskHandler }; const removeTodoTaskHandler = ({ id }) => { // Remove from the set of todo list }; const completeTodoTaskHandler = ({ id }) => { // Get item to remove }; return ( <div className="App"> <Header title={"My Tasks"} /> <Clock /> <div className="PageLayout"> <Suspense fallback={<div>Loading...</div>}> <TodoList payload={todoListPayload} completeTodoTaskHandler={completeTodoTaskHandler} /> <CompletedList list={completedTodoList} /> <AddNewTask addTodoTaskHandler={addTodoTaskHandler} /> </Suspense> </div> </div> ); } const rootElement = document.getElementById("root"); ReactDOM.render(<App />, rootElement);
You can find the demo link here, in case you want to play with it.
If we check the code in the demo, we’ll see:
<Suspense fallback={<div>Loading...</div>}> <TodoList payload={todoListPayload} completeTodoTaskHandler={completeTodoTaskHandler} /> <CompletedList list={completedTodoList} /> <AddNewTask addTodoTaskHandler={addTodoTaskHandler} /> </Suspense>
It is as simple as wrapping the components with Suspense. We lazily loaded some of the components — TodoList
, CompletedList
, AddNewTask
— using React.lazy()
. Since internally it will generate bundles for each, in slower network conditions, it might take some time to load them.
Suspense will automatically take care of that by showing a fallback
such as Loading… or any other component, such as a spinner or similar.
Great! Our short recap was intense. Now let’s have some more fun with Suspense.
Wait, haven’t we covered Suspense? Well, what if I told you Suspense can also handle our loading state when an API is called? But for that, we really need to dig into the API and understand it better.
After some digging and research, I finally found Shawn Swyx Wang’s 🌟 GitHub repository, and I would like to quote directly from his doc:
React Suspense is a generic way for components to suspend rendering while they load data from a cache.
Problems it solves: When rendering is I/O-bound.
OK, “load data from a cache” gave me a hint, but I needed more information on how I can really handle the API.
Kent C. Dodds taught an important concept in his Egghead lesson: Suspense automatically knows that an API request has been called if we throw a promise.
import React, { Suspense } from "react"; fetchArticles() { // Some fetch API fetching articles } let isRequestCalled = false; function Content() { let result = []; if (!cache) { const promise = fetchArticles(); isRequestCalled = true; throw promise; // Let suspense know } return <div>Article</div>; } const Articles = () => { return ( <div> {/* Yay promise is thrown */} <Suspense fallback={<div>loading...</div>}> <Content /> </Suspense> </div> ); }; export default Articles;
Of course, this isn’t the best way to handle code; it looks kinda hacky. So let’s try to use react-cache to handle this code better:
import React, { Suspense } from "react"; import { unstable_createResource as createResource } from "react-cache"; function fetchArticles() { // Some fetch API fetching articles } const politicalArticles = createResource(fetchArticles); function Content() { const result = politicalArticles.read(someKey); return <div>Article</div>; } const Articles = () => { return ( <div> <Suspense fallback={<div>loading...</div>}> <Content /> </Suspense> </div> ); }; export default Articles;
createResource
from react-cache creates a resource out of a callback, returning a promise.
Well, for Suspense to know that it has to show loading state, all it needs is a promise. It will continue to show the loading state until the promise is resolved.
However, this is experimental. I am sure you will run across errors, so don’t worry, it is clearly mentioned that react-cache is still under development.
Just a heads-up, make sure you use the read
method inside a component; otherwise, it will throw an error.
// A snippet from the React-cache library function readContext(Context, observedBits) { const dispatcher = ReactCurrentDispatcher.current; if (dispatcher === null) { throw new Error( 'react-cache: read and preload may only be called from within a ' + "component's render. They are not supported in event handlers or " + 'lifecycle methods.', ); } return dispatcher.readContext(Context, observedBits); }
In case you are interested in reading the react-cache source code, check this link.
We are now caught up on the near future of React, and one thing is evident: the React team wants to make the API as simple as possible.
I am also excited that more and more libraries are moving towards functional programming. This pattern will definitely revolutionize the way we write frontend. I am watching out for concurrent React, too — in case you are interested, check out the official roadmap docs. React-cache and Suspense are some of the features that are part of concurrent react 😎.
Follow me on Twitter to get updates regarding new articles and the latest frontend developments. Also, share this article on Twitter to help others find it. Sharing is caring ^_^
Install LogRocket via npm or script tag. LogRocket.init()
must be called client-side, not
server-side
$ npm i --save logrocket // Code: import LogRocket from 'logrocket'; LogRocket.init('app/id');
// Add to your HTML: <script src="https://cdn.lr-ingest.com/LogRocket.min.js"></script> <script>window.LogRocket && window.LogRocket.init('app/id');</script>
Hey there, want to help make our blog better?
Join LogRocket’s Content Advisory Board. You’ll help inform the type of content we create and get access to exclusive meetups, social accreditation, and swag.
Sign up nowDesign React Native UIs that look great on any device by using adaptive layouts, responsive scaling, and platform-specific tools.
Angular’s two-way data binding has evolved with signals, offering improved performance, simpler syntax, and better type inference.
Fix sticky positioning issues in CSS, from missing offsets to overflow conflicts in flex, grid, and container height constraints.
From basic syntax and advanced techniques to practical applications and error handling, here’s how to use node-cron.