在 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 请求和处理响应的复杂性,使用这种方法可确保干净且可维护的代码库,因为数据获取逻辑被封装并可在组件之间重用。
好了,我们已经介绍了处理CRUD操作的例子,下面我们来仔细看看Next.js提供的获取数据的方法,因为它作为一个框架,在React的基础上增加了它的功能和优化。很明显,Next.js 除了 CSR(客户端渲染)之外,还提供了高级功能,如 SSR(服务器端渲染)、SSG(静态站点生成)、内置 API 路由和混合渲染。那么,让我们讨论一下 Next.js 和 React 中检索数据的共性和差异。
只要 React 应用程序是纯粹的客户端,那么数据获取就会在初始页面加载后发生在客户端上。对于每次加载页面时都需要获取数据的动态页面,更适合使用SSR,在这种情况下,数据是在请求时在服务器上获取的。
对于 SSG,它适用于数据不经常更改的静态页面,数据是在构建时获取的。因此,getStaticProps 方法可以帮助我们
在构建时获取数据 (SSG)。如果我们需要基于动态路由和构建时获取的数据来预渲染页面,则 getStaticPaths 方法允许执行此操作。它与 getStaticProps 结合使用在构建时生成动态路由。需要注意的是,从 Next 14 开始,我们可以直接在组件中发出请求,而无需这些方法,从而提供了更多“React 体验”。
为了总结有关上述方法的信息,我们可以看一下表格,该表格全面概述了 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 提供了用于获取、缓存、同步和更新服务器状态的钩子,使其成为处理 React 和 Next.js 应用程序中数据的绝佳工具。使用它的主要好处是:
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 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中文网其他相关文章!