useSWR is my new favorite React library

Translation of the article prepared in advance of the start of the course “React.js developer”.


The last few months I have been working on an application on NextJS. Every week it becomes more and more. The application uses axios for API calls and unstated-next to manage the state. There are a lot of API calls, but we don’t want users to see a bunch of loading screens. Therefore we store call results axios at unstated storage facilities
.
However, we ran into a problem. Vaults themselves are becoming more and more complex. Pages sometimes require multiple API calls, and they in turn rely on the results of other API calls. Days turned into weeks and weeks into months, meanwhile our unstated vaults became more and more cumbersome. We ran into strange errors as our homemade caching logic struggled to deal with unexpected extreme cases.

Then we thought that the path should be simpler.
And here he is. And it is even designed Vercelcreator NextJS.

Get to know SWR

The name SWR comes from stale-while-revalidate, a caching method that is currently gaining popularity in frontend development. It allows you to download cached content immediately, and immediately updates it to handle new content in the future. In our case, we got the perfect compromise between performance and user experience.

How to use useSWR

useSWR Is a React hook library developed by Vercel. It allows you to retrieve data from an API or other external source, save it in the cache, and then render it.

Let’s start by looking at an example of a React component that gets a TODO list with JSON server, and renders it.

import React from "react";
import "./App.css";
const todosEndpoint = "http://localhost:3001/todos";
const TodoApp = () => {
  const [todos, setTodos] = React.useState([]);
  React.useEffect(() => {
    const getData = async () => {
      const response = await fetch(todosEndpoint);
      const data = await response.json();
      setTodos(data);
    };
     getData();
    }, []);
  return (
    
{todos.map((todo) => (
{todo.title}
))}
); }; export default TodoApp;

Now let’s look at the same component, but rewritten with useSWR.

import React from "react";
import useSWR from "swr";
const todosEndpoint = "http://localhost:3001/todos";
const getData = async () => {
  const response = await fetch(todosEndpoint);
  return await response.json();
};
const TodoApp = () => {
  const { data: todos } = useSWR(todosEndpoint, getData);
  
return (
     
      {todos && todos.map(todo => (
        
{todo.title}
)}
); }; export default TodoApp;

As you can see, it is very similar to the previous implementation.
In this example, we use useSWR (key, fetcher, options)to get our todo list. Key useSWR is needed for caching. In our case, we used todosEndpoint. As fetcher we passed an asynchronous function that retrieves a TODO list.

It should be noted that useSWR has no idea how you retrieve data. You can use any asynchronous data mining strategy that you like. you can use fetch, axios or even GraphQL. While your function is returning data asynchronously, useSWR will be happy.

Call useSWR returns the following parameters:

  • data: key data obtained with fetcher (not defined if not already loaded);
  • error: error caused by fetcher;
  • isValidating: a boolean that says whether a query or revalidation is being performed;
  • mutate (data ?, shouldRevalidate): function to change cached data.

More complex example

Let’s look at a more complex example that uses more parameters returned useSWR. In this example, we will retrieve one element of the TODO list and render the checkbox for the status complete our task from the list. When the checkbox is clicked, we send a PUT request to update TODO, and then call mutate to update the cache useSWR.

import React from "react";
import useSWR from "swr";
import "./App.css";
const todosEndpoint = "http://localhost:3001/todos";
const getTodo = async (id) => {
  const response = await fetch(`${todosEndpoint}/${id}`);
  return await response.json();
};
const updateTodo = async (id, todo) => {
  const response = await fetch(`${todosEndpoint}/${id}`, {
    method: "PUT",
    headers: {
      "Content-type": "application/json; charset=UTF-8",
    },
    body: JSON.stringify(todo),
  });
  return await response.json();
};
const TodoApp = () => {
  const todoId = 1;
  const key = `${todosEndpoint}/${todoId}`;
  const { data: todo, mutate } = useSWR(key, () =>
    getTodo(todoId)
  );
  const toggleCompleted = async () => {
    const newTodo = {
      ...todo,
      completed: !todo.completed,
    };
    await updateTodo(todoId, newTodo);
    mutate(newTodo);
  };
  if (!todo) {
    return  Loading...
; } return (

{todo.title}

); };

Using mutate Is a great way to increase the visible performance of your web application. We can change data locally and change the view, without waiting until the remote data source is updated. useSWR even revalidate and replace them with the latest data on the background.

Why do I need a library for this?

You may ask this question. Perhaps you already have a state management mechanism in your application, and you don’t see the point of using a third-party library for something as simple as data extraction and caching.

And I will answer you that caching data is not easy. And as your application grows, it gets even harder. You will encounter extreme cases, and processing them, you will get complex repositories and providers that are difficult to understand and difficult to maintain. Bugs will spill out of nowhere.

“In computer science, there are only two complex problems: cache invalidation and inventing names” – Phil Carleton

Instead of implementing your own data mining solution, why not rely on a proven solution developed by one of the most respected companies in the React ecosystem?

How useSWR helped us

Transferring the issue of data extraction in our application to useSWR gave many advantages.

1. He allowed us to remove the code

Pull requests that remove redundant code rather than add new code are my favorites. The less code in the application, the less likely it is that errors will occur. And this is good. As I age, I begin to appreciate simplicity more and more. useSWR allowed us to remove unstated storage completely, which simplified our application and made it easier to understand.

2. He simplified the connection of new developers to the project

useSWRlike most open source projects, it boasts excellent documentation. Implementing our own solution would mean that we need to write our own documentation and teach new developers in the project how to handle data extraction. Now when we use useSWR, we don’t need to do this.

3. He simplified difficult things

Our application, like most other applications, contains many API calls. Some of these calls depend on other API calls. WITH useSWR It’s easy to write hooks for dependent queries.

4. He improved visible performance.

The application looks faster. Users rated it and gave good feedback.

5. It updates obsolete data

useSWR updates outdated data in focus. This means that users always have the most up-to-date version of the data, excluding download time.

Conclusion

useSWR had a great impact on our application. This library has simplified our code and improved user experience. I can’t even imagine another library that would be as easy to implement and carry as many advantages as it has useSWR. To learn more about useSWR, you can visit site or repository on Github.

Alternative libraries

useSWR – This is not the only good library for data extraction. While it performed well in our case, perhaps another library is more suitable for you for data extraction.

React-query

react-query Is a library of hooks for retrieving, caching, and updating asynchronous data in React. This is a popular solution written by Tanner Linsi, very similar in scope to useSWR.

Apollo

Customer Apollo Is a client GraphQL, which will take care of extracting and caching your data, as well as updating the user interface. If you use GraphQLthen Apollo would be a great solution.


Learn more about the course.