今天,我将分享如何使用现代 React 模式构建一个精美的食品数据库管理系统。我们将专注于创建一个具有无缝乐观更新的响应式数据表,将 TanStack Query(以前称为 React Query)的强大功能与 Mantine 的组件库相结合。
首先,让我们定义我们的类型和 API 配置:
// Types export type GetAllFoods = { id: number; name: string; category: string; }; export type CreateNewFoodType = Pick< GetAllFoods, | 'name' | 'category' >; // API Configuration export const API = wretch('<http://localhost:9999>').options({ credentials: 'include', mode: 'cors', headers: { 'Content-Type': 'application/json', Accept: 'application/json', }, }); // TANSTACK QUERY export const getFoodOptions = () => { return queryOptions({ queryKey: ['all-foods'], queryFn: async () => { try { return await API.get('/foods') .unauthorized(() => { console.log('Unauthorized'); }) .json<Array<GetAllFoods>>(); } catch (e) { console.log({ e }); throw e; } }, }); }; export const useGetAllFoods = () => { return useQuery({ ...getFoodOptions(), }); };
使用 Mantine React Table 的表格组件:
const FoodsView = () => { const { data } = useGetAllFoods(); const columns = useMemo<MRT_ColumnDef<GetAllFoods>[]>( () => [ { accessorKey: 'id', header: 'ID', }, { accessorKey: 'name', header: 'Name', }, { accessorKey: 'category', header: 'Category', }, // ... other columns ], [] ); const table = useMantineReactTable({ columns, data: data ?? [], // Optimistic update animation mantineTableBodyCellProps: ({ row }) => ({ style: row.original.id < 0 ? { animation: 'shimmer-and-pulse 2s infinite', background: `linear-gradient( 110deg, transparent 33%, rgba(83, 109, 254, 0.2) 50%, transparent 67% )`, backgroundSize: '200% 100%', position: 'relative', } : undefined, }), }); return <MantineReactTable table={table} />; };
用于添加新食物的表单组件:
const CreateNewFood = () => { const { mutate } = useCreateNewFood(); const formInputs = [ { name: 'name', type: 'text' }, { name: 'category', type: 'text' }, ]; const form = useForm<CreateNewFoodType>({ initialValues: { name: '', category: '', // ... other fields }, }); return ( <Box mt="md"> <form onSubmit={form.onSubmit((data) => mutate(data))}> <Flex direction="column" gap="xs"> {formInputs.map((input) => ( <TextInput key={input.name} {...form.getInputProps(input.name)} label={input.name} tt="uppercase" type={input.type} /> ))} <Button type="submit" mt="md"> Create New </Button> </Flex> </form> </Box> ); };
我们实现的核心 - TanStack 查询突变与乐观更新:
export const useCreateNewFood = () => { const queryClient = useQueryClient(); return useMutation({ mutationKey: ['create-new-food'], mutationFn: async (data: CreateNewFoodType) => { await new Promise(resolve => setTimeout(resolve, 3000)); // Demo delay return API.url('/foods').post(data).json<GetAllFoods>(); }, onMutate: async (newFood) => { // Cancel in-flight queries await queryClient.cancelQueries({ queryKey: ['all-foods'] }); // Snapshot current state const previousFoods = queryClient.getQueryData<GetAllFoods[]>(['all-foods']); // Create optimistic entry const optimisticFood: GetAllFoods = { id: -Math.random(), ...newFood, verified: false, createdBy: 0, createdAt: new Date().toISOString(), updatedAt: new Date().toISOString(), }; // Update cache optimistically queryClient.setQueryData(['all-foods'], (old) => old ? [...old, optimisticFood] : [optimisticFood] ); return { previousFoods }; }, onError: (err, _, context) => { // Rollback on error if (context?.previousFoods) { queryClient.setQueryData(['all-foods'], context.previousFoods); } }, onSettled: () => { // Refetch to ensure consistency queryClient.invalidateQueries({ queryKey: ['all-foods'] }); }, }); };
动画将我们乐观的更新带入生活:
@keyframes shimmer-and-pulse { 0% { background-position: 200% 0; transform: scale(1); box-shadow: 0 0 0 0 rgba(83, 109, 254, 0.2); } 50% { background-position: -200% 0; transform: scale(1.02); box-shadow: 0 0 0 10px rgba(83, 109, 254, 0); } 100% { background-position: 200% 0; transform: scale(1); box-shadow: 0 0 0 0 rgba(83, 109, 254, 0); } }
在您的实施中考虑这些改进:
完成请求后
此实现演示了如何使用现代 React 模式创建强大的数据管理系统。 TanStack Query、Mantine UI 和深思熟虑的乐观更新的结合创造了流畅和专业的用户体验。
记住:
您在 React 应用程序中实施乐观更新时面临哪些挑战?在下面的评论中分享您的经验。
以上是构建乐观更新的数据表的详细内容。更多信息请关注PHP中文网其他相关文章!