mirror of
https://gitlab.com/djdietrick/docs
synced 2026-05-03 00:20:54 -04:00
Updated data fetching section of react
This commit is contained in:
@@ -2,6 +2,122 @@
|
|||||||
|
|
||||||
There are a few different ways to fetch data from a server in React using a Redux store. One note is that we should never make API calls within our reducers.
|
There are a few different ways to fetch data from a server in React using a Redux store. One note is that we should never make API calls within our reducers.
|
||||||
|
|
||||||
|
## React Router
|
||||||
|
|
||||||
|
React Router is a viable option for smaller projects that do not require larger state management. This can be accomplished by using the `loader` property on a route which can be used to fetch data.
|
||||||
|
|
||||||
|
```ts
|
||||||
|
// function for executing the query and returning the results
|
||||||
|
// ex. api/queries/searchPackages.ts
|
||||||
|
export interface PackageSummary {
|
||||||
|
name: string;
|
||||||
|
version: string;
|
||||||
|
description: string;
|
||||||
|
keywords?: string[];
|
||||||
|
}
|
||||||
|
|
||||||
|
interface SearchResponse {
|
||||||
|
objects: {
|
||||||
|
package: {
|
||||||
|
name: string;
|
||||||
|
description: string;
|
||||||
|
version: string;
|
||||||
|
keywords: string[];
|
||||||
|
};
|
||||||
|
}[];
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function searchPackages(term: string): Promise<PackageSummary[]> {
|
||||||
|
const res = await fetch(
|
||||||
|
`https://registry.npmjs.org/-/v1/search?text=${term}&size=10`
|
||||||
|
);
|
||||||
|
const data: SearchResponse = await res.json();
|
||||||
|
|
||||||
|
return data.objects.map(
|
||||||
|
({ package: { name, description, version, keywords } }) => {
|
||||||
|
return {
|
||||||
|
name,
|
||||||
|
description,
|
||||||
|
version,
|
||||||
|
keywords,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
```ts
|
||||||
|
// loader function, ex. pages/search/searchLoader.ts
|
||||||
|
import { searchPackages } from "../../api/queries/searchPackages";
|
||||||
|
import type { PackageSummary } from "../../api/queries/packageSummary";
|
||||||
|
|
||||||
|
export interface SearchLoaderResult {
|
||||||
|
searchResults: PackageSummary[];
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function searchLoader({
|
||||||
|
request, // request includes the url we are currently at in our router, can be parsed for query params
|
||||||
|
params, // named params in the route, ex. /packages/:name would be params.name
|
||||||
|
}: {
|
||||||
|
request: Request;
|
||||||
|
}): Promise<SearchLoaderResult> {
|
||||||
|
const { searchParams } = new URL(request.url);
|
||||||
|
const term = searchParams.get("term");
|
||||||
|
|
||||||
|
if (!term) {
|
||||||
|
throw new Error("Search term must be provided");
|
||||||
|
}
|
||||||
|
|
||||||
|
const results = await searchPackages(term);
|
||||||
|
|
||||||
|
// Good habit to return object, makes it easier to add more data in the future
|
||||||
|
return {
|
||||||
|
searchResults: results,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
```ts
|
||||||
|
// router
|
||||||
|
import { createBrowserRouter, RouterProvider } from "react-router-dom";
|
||||||
|
import Root from "./pages/Root";
|
||||||
|
import HomePage from "./pages/home/HomePage";
|
||||||
|
import { homeLoader } from "./pages/home/homeLoader";
|
||||||
|
import SearchPage from "./pages/search/SearchPage";
|
||||||
|
import { searchLoader } from "./pages/search/searchLoader";
|
||||||
|
|
||||||
|
const router = createBrowserRouter([
|
||||||
|
{
|
||||||
|
path: "/",
|
||||||
|
element: <Root />,
|
||||||
|
children: [
|
||||||
|
{
|
||||||
|
index: true,
|
||||||
|
element: <HomePage />,
|
||||||
|
loader: homeLoader,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
path: "/search",
|
||||||
|
element: <SearchPage />,
|
||||||
|
loader: searchLoader,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
]);
|
||||||
|
```
|
||||||
|
|
||||||
|
```ts
|
||||||
|
// in component
|
||||||
|
import { useLoaderData } from "react-router-dom";
|
||||||
|
import { SearchLoaderResult } from "./searchLoader";
|
||||||
|
|
||||||
|
export default function SearchPage() {
|
||||||
|
const { searchResults } = useLoaderData() as SearchLoaderResult;
|
||||||
|
|
||||||
|
// ... use search results
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
## Redux Toolkit Queries
|
## Redux Toolkit Queries
|
||||||
|
|
||||||
RTKQ is a library that allows you to create APIs to define how you want to query and manipulate your data via requests. It also automatically creates some hooks to let you know when data is loading, fetching, and functions to refetch, as well as hooks to automatically refetch data when some piece of data is changed by one of the API endpoints.
|
RTKQ is a library that allows you to create APIs to define how you want to query and manipulate your data via requests. It also automatically creates some hooks to let you know when data is loading, fetching, and functions to refetch, as well as hooks to automatically refetch data when some piece of data is changed by one of the API endpoints.
|
||||||
@@ -246,7 +362,3 @@ export default function UsersList() {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
## Redux Toolkit Query
|
|
||||||
|
|
||||||
RTK Query is an additional library that simplifies the above workflow by automatically creating the loading and error values for us. This works by creating APIs which define the endpoints you want to use to hit the server.
|
|
||||||
|
|||||||
Reference in New Issue
Block a user