做护肤品好的网站好网页游戏排行榜开心路
- 作者: 五速梦信息网
- 时间: 2026年04月18日 10:04
当前位置: 首页 > news >正文
做护肤品好的网站好,网页游戏排行榜开心路,在哪查看网站被收录的情况,宁波seo咨询文章目录 一、项目起航#xff1a;项目初始化与配置二、React 与 Hook 应用#xff1a;实现项目列表三、TS 应用#xff1a;JS神助攻 - 强类型四、JWT、用户认证与异步请求五、CSS 其实很简单 - 用 CSS-in-JS 添加样式六、用户体验优化 - 加载中和错误状态处理七、Hook… 文章目录 一、项目起航项目初始化与配置二、React 与 Hook 应用实现项目列表三、TS 应用JS神助攻 - 强类型四、JWT、用户认证与异步请求五、CSS 其实很简单 - 用 CSS-in-JS 添加样式六、用户体验优化 - 加载中和错误状态处理七、Hook路由与 URL 状态管理八、用户选择器与项目编辑功能九、深入React 状态管理与Redux机制十、用 react-query 获取数据管理缓存十一、看板页面及任务组页面开发1~34~6789.拖拽实现10.拖拽持久化 学习内容来源React React Hook TS 最佳实践-慕课网 相对原教程我在学习开始时2023.03采用的是当前最新版本 项版本react react-dom^18.2.0react-router react-router-dom^6.11.2antd^4.24.8commitlint/cli commitlint/config-conventional^17.4.4eslint-config-prettier^8.6.0husky^8.0.3lint-staged^13.1.2prettier2.8.4json-server0.17.2craco-less^2.0.0craco/craco^7.1.0qs^6.11.0dayjs^1.11.7react-helmet^6.1.0types/react-helmet^6.1.6react-query^6.1.0welldone-software/why-did-you-render^7.0.1emotion/react emotion/styled^11.10.6 具体配置、操作和内容会有差异“坑”也会有所不同。。。 一、项目起航项目初始化与配置 一、项目起航项目初始化与配置 二、React 与 Hook 应用实现项目列表 二、React 与 Hook 应用实现项目列表 三、TS 应用JS神助攻 - 强类型 三、 TS 应用JS神助攻 - 强类型 四、JWT、用户认证与异步请求 四、 JWT、用户认证与异步请求(上) 四、 JWT、用户认证与异步请求(下) 五、CSS 其实很简单 - 用 CSS-in-JS 添加样式 五、CSS 其实很简单 - 用 CSS-in-JS 添加样式(上) 五、CSS 其实很简单 - 用 CSS-in-JS 添加样式(下) 六、用户体验优化 - 加载中和错误状态处理 六、用户体验优化 - 加载中和错误状态处理(上) 六、用户体验优化 - 加载中和错误状态处理(中) 六、用户体验优化 - 加载中和错误状态处理(下) 七、Hook路由与 URL 状态管理 七、Hook路由与 URL 状态管理(上) 七、Hook路由与 URL 状态管理(中) 七、Hook路由与 URL 状态管理(下) 八、用户选择器与项目编辑功能 八、用户选择器与项目编辑功能(上) 八、用户选择器与项目编辑功能(下) 九、深入React 状态管理与Redux机制 九、深入React 状态管理与Redux机制(一) 九、深入React 状态管理与Redux机制(二) 九、深入React 状态管理与Redux机制(三) 九、深入React 状态管理与Redux机制(四) 九、深入React 状态管理与Redux机制(五) 十、用 react-query 获取数据管理缓存 十、用 react-query 获取数据管理缓存上 十、用 react-query 获取数据管理缓存下 十一、看板页面及任务组页面开发 1~3 十一、看板页面及任务组页面开发一 4~6 十一、看板页面及任务组页面开发二 78 十一、看板页面及任务组页面开发三 9.拖拽实现 接下来的内容将会是整个课程最难的部分相关知识也不是很常用 安装拖拽功能库 react-beautiful-dnd 及相关类型文件库 npm i react-beautiful-dnd ## –force npm i types/react-beautiful-dnd -D ## –force 接下来在原功能库的基础上自行二次封装 新建 src\components\grag-and-drop.tsx import React, { ReactNode } from react import { Draggable, DraggableProps, Droppable, DroppableProps, DroppableProvided, DroppableProvidedProps } from react-beautiful-dnd// 删除原有 “函数类型” children使用 ReactNode 类型的 children type DropProps OmitDroppableProps, children { children: ReactNode }export const Drop ({ children, …props }: DropProps) {return (Droppable {…props}{(provided) {if (React.isValidElement(children)) {return React.cloneElement(children, {…provided.droppableProps,ref: provided.innerRef,provided,});}return div /;}}/Droppable); };type DropChildProps Partial{ provided: DroppableProvided } DroppableProvidedProps React.HTMLAttributesHTMLDivElementexport const DropChild React.forwardRefHTMLDivElement, DropChildProps(({children, …props}, ref) div ref{ref} {…props} {children}{props.provided?.placeholder}/div );type DragProps OmitDraggableProps, children { children: ReactNode } export const Drag ({children, …props}: DragProps) {return Draggable {…props}{(provided {if(React.isValidElement(children)) {return React.cloneElement(children, {…provided.draggableProps,…provided.dragHandleProps,ref: provided.innerRef})}return div/})}/Draggable }forwardRef 是用作转发的经过包裹后的组件可以传入 ref 属性 Refs 转发 – React 这步报错ref: provided.innerRef Argument of type { ref: (element: HTMLElement | null) void; data-rbd-drag-handle-draggable-id?: string | undefined; data-rbd-drag-handle-context-id?: string | undefined; aria-describedby?: string | undefined; … 7 more …; onTransitionEnd?: React.TransitionEventHandler… | undefined; } is not assignable to parameter of type Partialunknown Attributes.Object literal may only specify known properties, and ref does not exist in type Partialunknown Attributes.接下来使用这个组件 编辑 src\screens\ViewBoard\index.tsx … import { DragDropContext } from react-beautiful-dnd; import { Drag, Drop, DropChild } from components/grag-and-drop;export const ViewBoard () {useDocumentTitle(看板列表);const { data: currentProject } useProjectInUrl();const { data: viewboards, isLoading: viewBoardIsLoading } useViewboards(useViewBoardSearchParams());const { isLoading: taskIsLoading } useTasks(useTasksSearchParams());const isLoading taskIsLoading || viewBoardIsLoading;return (DragDropContext onDragEnd{() {}}ViewContainerh1{currentProject?.name}看板/h1SearchPanel /{isLoading ? (Spin /) : (Drop typeCOLUMN directionhorizontal droppableIdviewboardColumnsContainer{viewboards?.map((vbd, index) (Drag key{vbd.id} draggableId{viewboard vbd.id} index{index}ViewboardColumn viewboard{vbd} key{vbd.id} //Drag))}CreateViewBoard //ColumnsContainer/Drop)}TaskModal //ViewContainer/DragDropContext); };export const ColumnsContainer styled(DropChild)display: flex;overflow-x: scroll;flex: 1; ;编辑 src\screens\ViewBoard\components\ViewboardCloumn.tsx 使组件可以透传 props 以及通过 forwardRef 转发 传入 ref: … export const ViewboardColumn React.forwardRefHTMLDivElement, { viewboard: Viewboard }(({ viewboard, …props }, ref) {const { data: allTasks } useTasks(useTasksSearchParams());const tasks allTasks?.filter((task) task.kanbanId viewboard.id);return (Container {…props} ref{ref}Rowh3{viewboard.name}/h3More viewboard{viewboard} key{viewboard.id}//RowTasksContainer{tasks?.map((task) (TaskCard key{task.id} task{task} /))}CreateTask kanbanId{viewboard.id} //TasksContainer/Container); });10.拖拽持久化 拖拽的时候 看板之间的间隔应该是不变的 编辑 src\screens\ViewBoard\index.tsx调整组件层级并显式使用 DropChild: … export const ViewBoard () {…return (DragDropContext onDragEnd{() {}}ViewContainerh1{currentProject?.name}看板/h1SearchPanel /{isLoading ? (Spin /) : (ColumnsContainerDrop typeCOLUMN directionhorizontal droppableIdviewboardDropChild style{{display: flex}}{viewboards?.map((vbd, index) (Dragkey{vbd.id}draggableId{viewboard vbd.id}index{index}ViewboardColumn viewboard{vbd} key{vbd.id} //Drag))}/DropChild/DropCreateViewBoard //ColumnsContainer)}TaskModal //ViewContainer/DragDropContext); };export const ColumnsContainer styled.divdisplay: flex;overflow-x: scroll;flex: 1; ;接下来做 任务拖拽排序 编辑 src\screens\ViewBoard\components\ViewboardCloumn.tsx: … import { Drag, Drop, DropChild } from components/grag-and-drop; … export const ViewboardColumn React.forwardRefHTMLDivElement,{ viewboard: Viewboard } (({ viewboard, …props }, ref) {const { data: allTasks } useTasks(useTasksSearchParams());const tasks allTasks?.filter((task) task.kanbanId viewboard.id);return (Container {…props} ref{ref}Rowh3{viewboard.name}/h3More viewboard{viewboard} key{viewboard.id} //RowTasksContainerDrop typeRow directionvertical droppableId{task viewboard.id}DropChild{tasks?.map((task, taskIndex) (Dragkey{task.id}draggableId{task task.id}index{taskIndex}TaskCard key{task.id} task{task} //Drag))}/DropChild/DropCreateTask kanbanId{viewboard.id} //TasksContainer/Container); });拖拽功能好了,接下来将拖拽结果持久化到数据库中 编辑 src\utils\use-optimistic-options.ts(看板和任务排序 获取URL参数为后续乐观更新做准备): … export const useReorderViewboardConfig (queryKey: QueryKey) useConfig(queryKey, (target, old) old ? [old, …target] : []);export const useReorderTaskConfig (queryKey: QueryKey) useConfig(queryKey, (target, old) old || []);编辑 src\utils\viewboard.ts(新增看板排序接口的 Custom Hook, SortProps 与 useReorderTask 共用): … export interface SortProps {// 要重新排序的 itemfromId: number;// 目标 itemreferenceId: number;// 放在目标 Item 的前还是后type: before | after;fromKanbanId?: number;toKanbanId?: number; }export const useReorderViewboard () {const client useHttp();return useMutation((params: SortProps) {return client(kanbans/reorder, {data: params,method: POST,});}, useReorderViewboardConfig(queryKey)); };编辑 src\utils\task.ts(新增看板排序接口的 Custom Hook): … export const useReorderTask (queryKey: QueryKey) {const client useHttp();return useMutation((params: SortProps) {return client(tasks/reorder, {data: params,method: POST,});}, useReorderTaskConfig(queryKey)); };编辑 src\screens\ViewBoard\index.tsx完善之前预留的 onDragEnd: … import { useReorderViewboard, useViewboards } from utils/viewboard; import {useProjectInUrl,useTasksQueryKey,useTasksSearchParams,useViewBoardQueryKey,useViewBoardSearchParams, } from ./utils; … import { useReorderTask, useTasks } from utils/task; … import { useCallback } from react;export const ViewBoard () {…const onDragEnd useDragEnd();return (DragDropContext onDragEnd{onDragEnd}…/DragDropContext); };export const useDragEnd () {const { data: viewboards } useViewboards(useViewBoardSearchParams());const { mutate: reorderViewBoard } useReorderViewboard(useViewBoardQueryKey());const { mutate: reorderTask } useReorderTask(useTasksQueryKey());const { data: allTasks [] } useTasks(useTasksSearchParams());return useCallback(({ source, destination, type }: DropResult) {if (!destination) {return;}// 看板排序if (type COLUMN) {const fromId viewboards?.[source.index].id;const toId viewboards?.[destination.index].id;if (!fromId || !toId || fromId toId) {return;}const type destination.index source.index ? after : before;reorderViewBoard({ fromId, referenceId: toId, type });}if (type ROW) {const fromKanbanId source.droppableId;const toKanbanId destination.droppableId;if (fromKanbanId toKanbanId) {return;}const fromTask allTasks.filter((task) task.kanbanId fromKanbanId)[source.index];const toTask allTasks.filter((task) task.kanbanId toKanbanId)[destination.index];if (fromTask?.id toTask?.id) {return;}reorderTask({fromId: fromTask?.id,referenceId: toTask?.id,fromKanbanId,toKanbanId,type:fromKanbanId toKanbanId destination.index source.index? after: before,});}},[viewboards, reorderViewBoard, allTasks, reorderTask]); }; …至此拖拽持久化完成查看效果验证 部分引用笔记还在草稿阶段敬请期待。。。
- 上一篇: 做互联网网站赚钱吗舟山网站网站建设
- 下一篇: 做花语的网站易语言如何做代刷网站
相关文章
-
做互联网网站赚钱吗舟山网站网站建设
做互联网网站赚钱吗舟山网站网站建设
- 技术栈
- 2026年04月18日
-
做红酒闪购的网站有哪些宁波高端网站设计价格
做红酒闪购的网站有哪些宁波高端网站设计价格
- 技术栈
- 2026年04月18日
-
做好网站建设通知怎么制作免费网站
做好网站建设通知怎么制作免费网站
- 技术栈
- 2026年04月18日
-
做花语的网站易语言如何做代刷网站
做花语的网站易语言如何做代刷网站
- 技术栈
- 2026年04月18日
-
做化妆品网站的意义深圳网站关键词
做化妆品网站的意义深圳网站关键词
- 技术栈
- 2026年04月18日
-
做画册好的国外网站推荐申请域名需要哪些资料
做画册好的国外网站推荐申请域名需要哪些资料
- 技术栈
- 2026年04月18日
