I just started learning React and I am creating a shortening URL application to play around with the tools. Below is the overall architecture of my program that would be helpful for the question that I would like to ask.
Both the Home
and UrlForm
components have access to the UrlContext
dispatcher to modify the state of the urls
. I am trying to implement pagination to my application, the endpoint to retrieve all the urls
associated to this user is /api/urls?size=5&page=0
(I’ve hardcoded the pagination for now to tackle the issue.
Just to summarise:
UrlForm button -> handleSubmit -> useCreateShortUrl -> creates URL in the backend -> dispatch to update the URL -> call getURL endpoint to retrieve the latest paginated URLs -> dispatch to update the URL state in React
export default function UrlForm() {
const [longUrl, setLongUrl] = useState("");
const { createShortUrl, shortUrl, error, isLoading }= useCreateShortUrl();
async function handleSubmit(e) { // event handler that will allow batch rendering
e.preventDefault();
await createShortUrl(longUrl);
}
import { useState } from "react";
import { useNavigate } from "react-router-dom";
import { useUrl } from "../contexts/UrlContext";
import { useAuth } from "../contexts/AuthContext";
export function useCreateShortUrl() {
const { token } = useAuth();
const { dispatch } = useUrl();
const [error, setError] = useState(null);
const [isLoading, setIsLoading] = useState(false);
const [shortUrl, setShortUrl] = useState("");
async function createShortUrl(longUrl) {
const customHeaders = new Headers();
customHeaders.append("Content-Type", "application/json");
customHeaders.append("Authorization", `Bearer ${localStorage.getItem("token")}`);
const requestOptions = {
method: "POST",
headers: customHeaders,
body: JSON.stringify({longUrl})
}
try {
const response = await fetch("api/urls", requestOptions);
const body = await response.json();
if (!response.ok) {
setIsLoading(false);
setError(body.message);
return;
}
setError(null);
setIsLoading(false);
buildShortUrl(body.shortUrlId);
dispatch({ type: "CREATE_URL", payload: body });
// updates the URL state to the correct pagination
const secondRequestOptions = {
method: 'GET',
headers: {
'Authorization': `Bearer ${token}`
}
};
const secondResponse = await fetch("/api/urls?size=5&page=0", secondRequestOptions)
const secondBody = await secondResponse.json();
if (!secondResponse.ok) {
setError(secondBody.message);
setIsLoading(false);
return;
}
setError(null);
setIsLoading(false);
let urls = []
if (secondBody._embedded) {
urls = secondBody._embedded.urls;
}
dispatch({ type: 'FETCH_URLS', payload: urls });
} catch(e) {
// server is probably down at this point
// response body can't pe parsed into JSON
setIsLoading(false);
setError("Server is down. Please try again later.");
}
}
function buildShortUrl(shortUrlId) {
// todo: replace with domain name, make it more flexible by retrieving from .env
const urlFormatter = `http://localhost:3000/urls/${shortUrlId}`
setShortUrl(urlFormatter);
}
return { createShortUrl, shortUrl, error, isLoading };
}
I know I can fix this issue just by removing the dispatch({ type: "CREATE_URL", payload: body });
which wouldn’t send a render into the queue. But just for understanding, I’m not sure why having that would still cause the issue since React would do batch rendering after the event handler UrlForm::handleSubmit
completes.
Image with debugger just before the issue
Image with debugger just after the issue (notice how there’s 6 images, that means the dispatcher
caused React to render and hence now urls
have 6 items)
Image at the end(notice now there’s only 5 times because after calling the fetch endpoint to retrieve the paginated urls, there should only be 5 URLs)
Side-question: How should I actually handle pagination when I create a new URL? Ideally I should only store the paginated number of URLs that’s requested by the user on the current page in the state (so I don’t have to store all the URLs from the database which could slow down the app) so that means I need a way to update the URL state everytime I create a URL just to maintain the correct number of URLs in the state to obey the paginated size.
Rust57 is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.