Categories
React

Making HTTP Requests with React Query — Parallel and Dependent Queries

The React Query library lets us make HTTP requests easily in our React apps.

In this article, we’ll look at how to make HTTP requests with React Query.

Parallel Queries

Sometimes, we may want to make multiple GET requests concurrently.

To do this, we can add multiple useQuery hooks:

index.js

import { StrictMode } from "react";
import ReactDOM from "react-dom";
import { QueryClient, QueryClientProvider } from "react-query";
import App from "./App";

const queryClient = new QueryClient();

const rootElement = document.getElementById("root");
ReactDOM.render(
  <QueryClientProvider client={queryClient}>
    <StrictMode>
      <App />
    </StrictMode>
  </QueryClientProvider>,
  rootElement
);

App.js

import axios from "axios";
import React from "react";
import { useQuery } from "react-query";
export default function App() {
  const { data } = useQuery({
    queryKey: ["todo", 1],
    queryFn: ({ queryKey: [, id] }) => {
      return axios(`https://jsonplaceholder.typicode.com/posts/${id}`);
    }
  });
  const { data: yesNoData } = useQuery("yesNo", () =>
    axios("https://yesno.wtf/api")
  );

  return (
    <div>
      <div>{JSON.stringify(data)}</div>
      <div>{JSON.stringify(yesNoData)}</div>
    </div>
  );
}

We have useQuery hooks to make 2 requests in parallel.

Dynamic Parallel Queries with useQueries Hook

We can add dynamic parallel queries with the useQueries hook.

It returns an array of query results.

For instance, we can write:

import axios from "axios";
import React from "react";
import { useQueries } from "react-query";
export default function App() {
  const todos = useQueries(
    Array(5)
      .fill()
      .map((_, i) => i + 1)
      .map((id) => {
        return {
          queryKey: ["todo", id],
          queryFn: ({ queryKey: [, id] }) => {
            return axios(`https://jsonplaceholder.typicode.com/posts/${id}`);
          }
        };
      })
  );

  return (
    <div>
      <div>{JSON.stringify(todos)}</div>
    </div>
  );
}

We call useQueries with an array of query objects.

We call map to map the array of numbers we created with:

Array(5)
  .fill()
  .map((_, i) => i + 1)

to query objects.

And todos is an array of query objects.

Dependent Queries

We can make also make multiple HTTP requests where one depends on the other.

To do this, we write:

import axios from "axios";
import React from "react";
import { useQuery } from "react-query";
export default function App() {
  const { data: id } = useQuery("id", () => Promise.resolve(1));

  const { data } = useQuery(
    ["todo", id],
    ({ queryKey: [, id] }) => {
      return axios(`https://jsonplaceholder.typicode.com/posts/${id}`);
    },
    {
      enabled: Boolean(id)
    }
  );

  return (
    <div>
      <div>{JSON.stringify(data)}</div>
    </div>
  );
}

to make one query after the other.

We call the first useQuery hook to get an id for our todo.

Then we call useQuery again to pass in the id to the callback.

We set the enabled property to a boolean expression to indicate when we want to query to run.

We set it so that the 2nd query is run when id is truthy, which should only happen when we get the id from the first useQuery hook.

Conclusion

We can make parallel or sequential queries with React Query easily.

Categories
React

Making HTTP Requests with React Query — Query Functions

The React Query library lets us make HTTP requests easily in our React apps.

In this article, we’ll look at how to make HTTP requests with React Query.

Query Functions

Query functions are functions that returns a promise and it’s passed into the 2nd argument of the useQuery hook.

For instance, we can write:

index.js

import { StrictMode } from "react";
import ReactDOM from "react-dom";
import { QueryClient, QueryClientProvider } from "react-query";
import App from "./App";

const queryClient = new QueryClient();

const rootElement = document.getElementById("root");
ReactDOM.render(
  <QueryClientProvider client={queryClient}>
    <StrictMode>
      <App />
    </StrictMode>
  </QueryClientProvider>,
  rootElement
);

App.js

import axios from "axios";
import React from "react";
import { useQuery } from "react-query";
export default function App() {
  const { data } = useQuery("yesNo", () => axios("https://yesno.wtf/api"));

  return <div>{JSON.stringify(data)}</div>;
}

to return the promise return by the axios function.

The returned promises’ data will be set as the value of the data property.

Handling and Throwing Errors

React Query expects that an error is thrown in the query function when an error occurred.

If it doesn’t then we’ve to throw it ourselves.

For instance, we can write:

import React from "react";
import { useQuery } from "react-query";
export default function App() {
  const { error } = useQuery("todo", async () => {
    const response = await fetch(
      "https://jsonplaceholder.typicode.com/posts/100000000000"
    );
    if (!response.ok) {
      throw new Error("Network response was not ok");
    }
    return response.json();
  });

  return <div>{error && error.message}</div>;
}

If we use the Fetch API to make HTTP requests, then we’ve to check whether the response.ok property is true .

If it’s not, then we’ve to throw an error to let React Query know that an error has occurred.

This has to be done since fetch doesn’t throw an error when we get a non-200 series response.

If response.ok is true , we return the response by calling response.json() .

Query Object

We can pass in a query object instead of pass in every as separate arguments to make our GET request.

For instance, we can write:

import axios from "axios";
import React from "react";
import { useQuery } from "react-query";
export default function App() {
  const { data } = useQuery({
    queryKey: ["todo", 1],
    queryFn: ({ queryKey: [, id] }) => {
      return axios(`https://jsonplaceholder.typicode.com/posts/${id}`);
    }
  });

  return <div>{JSON.stringify(data)}</div>;
}

queryKey has the identifier of the request.

queryFn is the function for making the request.

Conclusion

We can pass in functions that returns a promise to make requests to the useQuery hook to make GET requests with React.

Categories
React

Making HTTP Requests with React Query — GET Requests

The React Query library lets us make HTTP requests easily in our React apps.

In this article, we’ll look at how to make HTTP requests with React Query.

GET Requests with the useQuery Hook

To make GET requests, we use the useQuery hook provided by React Query.

For instance, we can write:

index.js

import { StrictMode } from "react";
import ReactDOM from "react-dom";
import { QueryClient, QueryClientProvider } from "react-query";
import App from "./App";

const queryClient = new QueryClient();

const rootElement = document.getElementById("root");
ReactDOM.render(
  <QueryClientProvider client={queryClient}>
    <StrictMode>
      <App />
    </StrictMode>
  </QueryClientProvider>,
  rootElement
);

App.js

import axios from "axios";
import React from "react";
import { useQuery } from "react-query";

export default function App() {
  const { isLoading, isError, data, error } = useQuery("yesNo", () =>
    axios("https://yesno.wtf/api")
  );

  if (isLoading) {
    return <span>Loading...</span>;
  }

  if (isError) {
    return <span>Error: {error.message}</span>;
  }

  return <div>{JSON.stringify(data)}</div>;
}

We wrap our App with the QueryClientProvider higher-order component to let us use the hooks provided by React Query to make HTTP requests.

Then in App , we call useQuery with an identifier for the request as the first argument.

The 2nd argument has the function that makes the HTTP request.

It should return a promise with the response data.

The hook returns an object with various properties.

isLoading is true when the request is loading.

isError is true when the request has an error.

data has the response data.

error has the error content.

We can replace the boolean properties with the status property.

For instance, we can write:

import axios from "axios";
import React from "react";
import { useQuery } from "react-query";

export default function App() {
  const { status, data, error } = useQuery("yesNo", () =>
    axios("https://yesno.wtf/api")
  );

  if (status === "loading") {
    return <span>Loading...</span>;
  }

  if (status === "error") {
    return <span>Error: {error.message}</span>;
  }

  return <div>{JSON.stringify(data)}</div>;
}

If status is 'loading' , then the request is loading.

If status is 'error' , then the request has an error.

Query Keys

Query keys are the first argument of the useQuery .

It identifies the request being made uniquely.

We can pass in a string as we did in the above examples.

But we can also pass in array keys if we need to pass in more information to identify the request.

For instance, we can write:

import axios from "axios";
import React from "react";
import { useQuery } from "react-query";

export default function App() {
  const { status, data, error } = useQuery(
    ["todo", 5],
    ({ queryKey: [, id] }) => {
      return axios(`https://jsonplaceholder.typicode.com/posts/${id}`);
    }
  );

  if (status === "loading") {
    return <span>Loading...</span>;
  }

  if (status === "error") {
    return <span>Error: {error.message}</span>;
  }

  return <div>{JSON.stringify(data)}</div>;
}

to call useQuery with an array key.

We can get the key’s content with the queryKey property of the parameter in the callback in the 2nd argument.

We get the id from the 2nd entry of the array just like how we passed them in.

Conclusion

We can make GET requests easily in our React app with React Query.

Categories
React

Getting Started with Making HTTP Requests with React Query

The React Query library lets us make HTTP requests easily in our React apps.

In this article, we’ll look at how to make HTTP requests with React Query.

Installation

We can install the library by running:

npm i react-query

or:

yarn add react-query

We also install the Axios HTTP client library to let us make requests easier.

To do this, we run:

npm i axios

Getting Started

We can then make a query with the API by writing:

index.js

import { StrictMode } from "react";
import ReactDOM from "react-dom";
import { QueryClient, QueryClientProvider } from "react-query";
import App from "./App";

const queryClient = new QueryClient();

const rootElement = document.getElementById("root");
ReactDOM.render(
  <QueryClientProvider client={queryClient}>
    <StrictMode>
      <App />
    </StrictMode>
  </QueryClientProvider>,
  rootElement
);

App.js

import axios from "axios";
import React from "react";
import { useQuery } from "react-query";

export default function App() {
  const { isLoading, error, data } = useQuery("yesNo", () =>
    axios("https://yesno.wtf/api")
  );

  if (isLoading) return "Loading...";

  if (error) return "An error has occurred: " + error.message;

  return <div>{JSON.stringify(data)}</div>;
}

We wrap our App component around the QueryClientProvider component to let us use its hooks to make requests.

Then in App , we use the useQuery hook to make a GET request.

The first argument is a string identifier for our query.

The 2nd argument has a function to let us make the request.

The isLoading state indicates the request is loading when it’s truthy.

error state indicates that an error occurred when it’s truthy.

data has the response data.

Making POST Requests

To make POST requests, we can use the useMutation hook.

To do this, we write:

import axios from "axios";
import React from "react";
import { useMutation, useQueryClient } from "react-query";

export default function App() {
  const queryClient = useQueryClient();
  const mutation = useMutation(
    (data) => axios.post("https://jsonplaceholder.typicode.com/posts", data),
    {
      onSuccess: () => {
        queryClient.invalidateQueries("todos");
      }
    }
  );

  return (
    <div>
      <button
        onClick={() => {
          mutation.mutate({
            title: "foo",
            body: "bar",
            userId: 1
          });
        }}
      >
        Add Todo
      </button>
    </div>
  );
}

We keep index.js the same as in the previous example.

We call the useQueryClient hook to get the query client.

useMutation lets us make the request by passing in a callback that returns a promise by calling axios.post with the URL and request body we want.

The 2nd argument has an object that has the onSuccess callback that runs when the request succeeds.

We call queryClient.invalidaQueries with the identifier of the requests to clear resources.

Conclusion

We can make HTTP requests easily with the React Query library.

Categories
React

Add Infinite Scrolling to a React App with the Intersection Observer API

Infinite scrolling is something that we’ve to add often into our React app.

In this article, we’ll look at how to add infinite scrolling to a React app with the Intersection Observer API.

Add Infinite Scrolling with the Intersection Observer API

The Intersection Observer API lets us add infinite scrolling easily within our React app because we can use it to detect the element at the bottom of the list.

We assign a ref to the element at the bottom of the page, then we can use the Intersection Observer API to detect when it crosses the screen’s edge and displayed on the page.

To do this, we write:

import { useEffect, useRef, useState } from "react";
export default function App() {
  const lastItemRef = useRef();
  const observer = useRef();
  const [arr, setArr] = useState(
    Array(30)
      .fill()
      .map((_, i) => i)
  );
  const [page, setPage] = useState(1);

  useEffect(() => {
    const options = {
      root: document,
      rootMargin: "20px",
      threshold: 1
    };
    const callback = (entries) => {
      if (entries[0].isIntersecting) {
        const newPage = page + 1;
        setArr((arr) => [
          ...arr,
          ...Array(30)
            .fill()
            .map((_, i) => i + 30 * (newPage - 1))
        ]);
        setPage(newPage);
      }
    };
    observer.current = new IntersectionObserver(callback, options);
    if (lastItemRef.current) {
      observer.current.observe(lastItemRef.current);
    }
    return () => {
      observer.current.disconnect();
    };
  });
  return (
    <div className="App">
      {arr.map((a, i) => {
        if (i === arr.length - 1) {
          return (
            <p key={a} ref={lastItemRef}>
              {a}
            </p>
          );
        }
        return <p key={a}>{a}</p>;
      })}
    </div>
  );
}

We have the lastItemRef which is the ref which we assign to the bottom element of the page.

observer is a ref that we use to store the observer.

arr is what we render onto the page.

We have the page element to tell us what page we’re at.

Then we have the useEffect hook with a callback that has the options object to store the options for the Intersection Observer.

root is the scroll container, which is the document object. This is the html element.

rootMargin is how near is the element we’re observing is at the edge of the screen for it to be considered to be intersecting with the edge of the screen.

threshold means how much the observed element is visible within the elements specified by the root option for the callback top to be run.

Then we have the callback to check whether isIntersecting is true for it to be considered an intersection.

Then we call setArr to add more items to arr if it’s true .

Then we call observe with the element that we’re observing, which is stored in lastItemRef current.

And we return a callback that calls disconnect to clear the intersection observer when the component unmounts.

Finally, we render the arr items into p elements, and we ass the lastItemRef to the element that’s rendered last, which is the one at the bottom of the screen.

Conclusion

We can use the Intersection Observer API to add infinite scrolling to our React app easily.