首页 >web前端 >js教程 >使用 NextJS 掌握 CRUD

使用 NextJS 掌握 CRUD

Barbara Streisand
Barbara Streisand原创
2024-12-15 17:47:14684浏览

Mastering CRUD with NextJS

在 Web 开发中,CRUD 操作是基本构建块,对于管理数据至关重要。它们几乎在每个应用程序中无处不在,从简单的网站到复杂的企业解决方案。

NestJS Boilerplate 用户已经能够评估和使用功能强大的新工具 - CLI,它允许您自动创建资源及其属性。使用此工具,您可以进行所有 CRUD 操作并向其中添加必要的字段,而无需手动编写一行代码。同时,正如我们一再宣布的,BC Boilerplates 生态系统包括一个完全兼容的 Extective-React-Boilerplate,以提供完整的功能(原则上,它可以是一个完全独立的解决方案)。现在让我们从前端角度探讨一下 CRUD 操作。

在具有服务器端渲染功能的 React 框架 Next.js 中,可以通过增强性能、SEO 和开发人员体验的功能来有效管理这些操作。之前,我们发表了一篇关于启动 NextJS 项目的有效方法的文章,现在我们想进一步分析使用 Next.js 中的 API 的细节和细微差别。

众所周知,CRUD 缩写代表创建、读取、更新和删除。这个概念代表了可以对任何数据执行的基本操作。让我们考虑使用管理面板用户的示例来处理 CRUD 操作,其中实现了添加、编辑和删除用户等功能,以及检索有关用户的信息。下面讨论的自定义 React 钩子,用于处理 React Query 中的数据处理、分页、错误管理等,已经集成到 Extective-React-Boilerplate 中。当然,您可以直接利用这个样板。在以下部分中,我们将分享我们对实现这些功能的见解。

创建操作

用例:提交数据以创建新资源(例如,用户注册、添加新产品)。
实现: 从表单收集数据,向服务器发送 POST 请求,处理响应,并相应地更新 UI。

让我们观察一个例子。向 API 发出 POST 请求会合并创建新用户。在下面的代码片段中,usePostUserService 钩子用于封装此逻辑。我们已经通过定义请求和响应类型来指定创建新用户的数据结构,但这里省略这一部分以帮助您集中注意力。您可以在存储库 Extective-React-Boilerplate 中查看更详细的信息或更完整的图片,因为此代码片段以及以下所有代码片段都来自那里。
因此,我们将创建一个自定义挂钩 usePostUserService,它使用 useFetch 挂钩发送 POST 请求。它将用户数据作为输入并将其发送到 API:

function usePostUserService() {
  const fetch = useFetch();
  return useCallback(
    (data: UserPostRequest, requestConfig?: RequestConfigType) => {
      return fetch(`${API_URL}/v1/users`, {
        method: "POST",
        body: JSON.stringify(data),
        ...requestConfig,
      }).then(wrapperFetchJsonResponse<UserPostResponse>);
    },
    [fetch]
  );
}

函数wrapperFetchJsonResponse 将在本文稍后讨论“错误处理”时进行研究。

读操作

用例:获取并显示资源列表或单个资源(例如,获取用户配置文件和产品列表)。
实现:发送 GET 请求来获取数据,处理加载和错误状态,并在 UI 中呈现数据。

在我们的示例中,读取数据涉及向 API 发出 GET 请求以获取用户数据。它可以包括使用分页、过滤器获取所有用户,以及在定义请求 (UsersRequest) 和响应类型 (UsersResponse) 后按 ID 排序或获取单个用户。
要在自定义 useGetUsersService 挂钩中获取所有用户,我们发送带有用于分页、过滤器和排序的查询参数的 GET 请求:

function useGetUsersService() {
  const fetch = useFetch();

  return useCallback(
    (data: UsersRequest, requestConfig?: RequestConfigType) => {
      const requestUrl = new URL(`${API_URL}/v1/users`);
      requestUrl.searchParams.append("page", data.page.toString());
      requestUrl.searchParams.append("limit", data.limit.toString());
      if (data.filters) {
        requestUrl.searchParams.append("filters", JSON.stringify(data.filters));
      }
      if (data.sort) {
        requestUrl.searchParams.append("sort", JSON.stringify(data.sort));
      }

      return fetch(requestUrl, {
        method: "GET",
        ...requestConfig,
      }).then(wrapperFetchJsonResponse<UsersResponse>);
    },
    [fetch]
  );
}

用于获取单个用户 useGetUserService 挂钩发送 GET 请求以按 ID 获取用户:

function useGetUserService() {
  const fetch = useFetch();
  return useCallback(
    (data: UserRequest, requestConfig?: RequestConfigType) => {
      return fetch(`${API_URL}/v1/users/${data.id}`, {
        method: "GET",
        ...requestConfig,
      }).then(wrapperFetchJsonResponse<UserResponse>);
    },
    [fetch]
  );
}

更新操作

用例:编辑现有资源(例如,更新用户信息、编辑博客文章)。
实现:收集更新的数据,向服务器发送 PUT 或 PATCH 请求,处理响应,并更新 UI。

让我们更新现有用户,这涉及到使用更新的用户数据向 API 发送 PATCH 请求。为此,在自定义 usePatchUserService 挂钩中,我们在定义请求 UserPatchRequest 和响应类型 UserPatchResponse 后发送带有用户 ID 和更新数据的 PATCH 请求:

function usePatchUserService() {
  const fetch = useFetch();
  return useCallback(
    (data: UserPatchRequest, requestConfig?: RequestConfigType) => {
      return fetch(`${API_URL}/v1/users/${data.id}`, {
        method: "PATCH",
        body: JSON.stringify(data.data),
        ...requestConfig,
      }).then(wrapperFetchJsonResponse<UserPatchResponse>);
    },
    [fetch]
  );
}

注意:对于部分数据更新,使用 PATCH 代替 PUT 更为高级,而 PUT 通常用于完整资源更新。

删除操作

用例:删除资源(例如,删除用户或从列表中删除项目)。
实现: 向服务器发送 DELETE 请求,处理响应,并更新 UI 以反映删除。

在我们的下一个示例中,删除用户涉及使用用户 ID 向您的 API 发送 DELETE 请求。在 useDeleteUsersService 挂钩中定义请求 (UsersDeleteRequest) 和响应类型 (UsersDeleteResponse) 后,将传输 DELETE 请求以通过 ID 删除用户。

function usePostUserService() {
  const fetch = useFetch();
  return useCallback(
    (data: UserPostRequest, requestConfig?: RequestConfigType) => {
      return fetch(`${API_URL}/v1/users`, {
        method: "POST",
        body: JSON.stringify(data),
        ...requestConfig,
      }).then(wrapperFetchJsonResponse<UserPostResponse>);
    },
    [fetch]
  );
}

这些钩子抽象了发出 HTTP 请求和处理响应的复杂性,使用这种方法可确保干净且可维护的代码库,因为数据获取逻辑被封装并可在组件之间重用。

在 Next.js 中检索数据

好了,我们已经介绍了处理CRUD操作的例子,下面我们来仔细看看Next.js提供的获取数据的方法,因为它作为一个框架,在React的基础上增加了它的功能和优化。很明显,Next.js 除了 CSR(客户端渲染)之外,还提供了高级功能,如 SSR(服务器端渲染)、SSG(静态站点生成)、内置 API 路由和混合渲染。那么,让我们讨论一下 Next.js 和 React 中检索数据的共性和差异。

只要 React 应用程序是纯粹的客户端,那么数据获取就会在初始页面加载后发生在客户端上。对于每次加载页面时都需要获取数据的动态页面,

更适合使用SSR,在这种情况下,数据是在请求时在服务器上获取的。 对于 SSG,它适用于数据不经常更改的静态页面,数据是在构建时获取的。因此,getStaticProps 方法可以帮助我们
在构建时获取数据 (SSG)。如果我们需要基于动态路由和构建时获取的数据来预渲染页面,则 getStaticPaths 方法允许执行此操作。它与 getStaticProps 结合使用在构建时生成动态路由。需要注意的是,从 Next 14 开始,我们可以直接在组件中发出请求,而无需这些方法,从而提供了更多“React 体验”。

使用 useQuery 进行客户端数据获取可用于需要在客户端获取数据的交互式组件,其初始状态是从服务器端获取的数据中获取的。对于获取频繁更改的数据或添加客户端交互性,useSWR 策略非常有用。它是一个用于客户端数据获取、缓存和重新验证的 React 钩子。它允许在客户端获取数据,通常是在初始页面加载之后。尽管如此,它不会在构建时或在 SSR 服务器上获取数据,但它可以在需要时重新验证并获取新数据。

为了总结有关上述方法的信息,我们可以看一下表格,该表格全面概述了 Next.js 中的不同数据获取方法,突出显示了它们各自的时间和用例。

Method Data Fetching Timing Use Case
getStaticPaths Static Site Generation (SSG) At build time Pre-render pages for dynamic routes based on data available at build time.
getStaticProps Static Site Generation (SSG) At build time Pre-render pages with static content at build time. Ideal for content that doesn't change frequently.
getServerSideProps Server-Side Rendering (SSR) On each request Fetch data on the server for each request, providing up-to-date content. Ideal for dynamic content that changes frequently.
useQuery Client-Side Rendering (CSR) After the initial page load Fetch initial data server-side, hydrate, reduce redundant network requests, Background Refetching.
useSWR Client-Side Rendering (CSR) After the initial page load Fetch and revalidate data on the client-side, suitable for frequently changing data.

将 React Query 与 Next.js 结合使用

React Query 提供了用于获取、缓存、同步和更新服务器状态的钩子,使其成为处理 React 和 Next.js 应用程序中数据的绝佳工具。使用它的主要好处是:

  • 高效的数据获取:它处理缓存和后台数据同步,减少冗余的网络请求。
  • 自动重新获取:数据过时时可以在后台自动重新获取,确保UI始终显示最新信息。
  • 集成错误处理:内置对处理错误和重试的支持,使管理网络故障和服务器错误变得更加容易。
  • 乐观更新: useMutation 钩子通过提供一种简单的方法来处理乐观 UI 更改和服务器请求失败时的回滚逻辑,从而提供乐观更新。
  • 易于与 Next.js 集成:它可以与 getStaticProps 或 getServerSideProps(如果需要)等其他 Next.js 数据获取方法无缝集成。
  • 检查查询和突变:ReactQueryDevtools 工具提供了查看所有活动查询和突变的状态、数据、错误和其他详细信息的可能性,并在应用程序运行时实时观察查询状态更新.

查询客户端提供者

QueryClientProvider 是一个上下文提供者组件,它向 React 组件树提供 QueryClient 实例。这个实例对于使用像 useQuery 这样的钩子是必需的。 要进行设置,需要将其放置在组件树的根部,并为查询和突变配置全局设置,例如重试行为、缓存时间等。之后,它会初始化 React Query 客户端并使其在整个应用程序中可用。

function usePostUserService() {
  const fetch = useFetch();
  return useCallback(
    (data: UserPostRequest, requestConfig?: RequestConfigType) => {
      return fetch(`${API_URL}/v1/users`, {
        method: "POST",
        body: JSON.stringify(data),
        ...requestConfig,
      }).then(wrapperFetchJsonResponse<UserPostResponse>);
    },
    [fetch]
  );
}

那么,为什么要把它添加到项目中呢?它有益于:

  • 所有查询和突变的集中配置。
  • 易于设置并集成到现有的 React 应用程序中。
  • 启用缓存、后台重新获取和查询失效等功能。

React 查询开发工具

React Query 提供的另一个重要功能是 React Query Devtools - 一个用于检查和调试 React Query 状态的开发工具。它可以轻松添加到您的应用程序中,并通过浏览器扩展或作为组件进行访问,如前面的示例所示。
在开发过程中,React Query Devtools 可用于检查单个查询和突变,了解为什么某些查询会预取并监视查询缓存的状态,并查看它如何随着时间的推移而演变。

分页和无限滚动

要使用库中的功能实现分页控件或无限滚动,useInfiniteQuery 是完美的选择。首先,我们生成唯一的键,用于在 React Query 中缓存和检索查询。这里的 by 方法根据排序和过滤选项创建唯一键。

function usePostUserService() {
  const fetch = useFetch();
  return useCallback(
    (data: UserPostRequest, requestConfig?: RequestConfigType) => {
      return fetch(`${API_URL}/v1/users`, {
        method: "POST",
        body: JSON.stringify(data),
        ...requestConfig,
      }).then(wrapperFetchJsonResponse<UserPostResponse>);
    },
    [fetch]
  );
}

为此,我们将使用 React Query 中的 useInfiniteQuery 函数,并采用上面读取操作部分中讨论的 useGetUsersService 挂钩。

function useGetUsersService() {
  const fetch = useFetch();

  return useCallback(
    (data: UsersRequest, requestConfig?: RequestConfigType) => {
      const requestUrl = new URL(`${API_URL}/v1/users`);
      requestUrl.searchParams.append("page", data.page.toString());
      requestUrl.searchParams.append("limit", data.limit.toString());
      if (data.filters) {
        requestUrl.searchParams.append("filters", JSON.stringify(data.filters));
      }
      if (data.sort) {
        requestUrl.searchParams.append("sort", JSON.stringify(data.sort));
      }

      return fetch(requestUrl, {
        method: "GET",
        ...requestConfig,
      }).then(wrapperFetchJsonResponse<UsersResponse>);
    },
    [fetch]
  );
}

这里的 QueryFn 根据当前页面、过滤器和排序参数检索用户数据,而 getNextPageParam 函数根据上一页的响应确定要获取的下一页。当用户滚动或请求更多数据时,useInfiniteQuery 会根据 nextPage 参数自动检索下一组数据 - 这就是无限滚动发生的方式。查询的缓存时间由 gcTime 参数设置。

总的来说,React Query 提供了一个用于管理和调试 React 应用程序中服务器状态的全面解决方案。 QueryClientProvider 确保所有查询和突变的集中且一致的配置,而 ReactQueryDevtools 提供强大的工具用于在开发过程中检查和理解查询行为。

错误处理

实现 CRUD 操作始终需要适当的错误处理,以确保用户友好性和应用程序可靠性。服务器错误通常与客户端请求处理失败、服务器代码错误、资源过载、基础设施配置错误或外部服务故障相关。对于错误处理,Extective-react-boilerplate 建议使用wrapperFetchJsonResponse 函数:

function useGetUserService() {
  const fetch = useFetch();
  return useCallback(
    (data: UserRequest, requestConfig?: RequestConfigType) => {
      return fetch(`${API_URL}/v1/users/${data.id}`, {
        method: "GET",
        ...requestConfig,
      }).then(wrapperFetchJsonResponse<UserResponse>);
    },
    [fetch]
  );
}

结论

在本文中,我们介绍了基本的 CRUD 操作,探索了 NextJS 中的数据检索技术。我们深入研究了使用 React Query 来管理状态,还概述了 QueryClientProvider 和 ReactQueryDevtools 用于调试和优化数据检索的功能。此外,我们还讨论了如何实现分页和无限滚动来处理大型数据集,并解决了错误处理问题,使您的应用程序更具弹性并确保流畅的用户体验。

通过遵循本文中概述的示例和技术,您现在应该能够在 NextJS 项目中处理 CRUD 操作。或者,您可以为您的项目使用我们的 Extective-react-boilerplate 模板。它具有完全兼容的 Nestjs-boilerplate 后端,可以在几分钟内实现使用 CRUD 操作的能力,而无需使用 CLI 编写一行代码,我们已在此处和此处针对实体关系更详细地介绍了这一点。不断尝试,随时了解最佳实践,如果您发现它有用,欢迎尝试此样板。

我们的 BC Boilerplates 团队始终在寻找加强开发的方法。我们很想听听您对 GitHub 讨论或下面评论的想法。

本文全部归功于 Olena Vlasenko 和 Vlad Shchepotin ??

以上是使用 NextJS 掌握 CRUD的详细内容。更多信息请关注PHP中文网其他相关文章!

声明:
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn