☰
基于 React 19 + TypeScript + Vite 构建可搜索、可分页的用户数据表格(data-table-app 实战指南)
2026/9/30 1:45:42 网站建设 项目流程
  • 前端
  • 教程
  • 文档

【免费下载链接】reactjs-interview-questions

List of top 500 ReactJS Interview Questions & Answers....Coding exercise questions are coming soon!!

项目地址:https://gitcode.com/GitHub_Trending/re/reactjs-interview-questions
点击查看免费下载

本文以仓库中的>import { defineConfig } from 'vite' import react from '@vitejs/plugin-react' export default defineConfig({ plugins: [react()], })

@vitejs/plugin-react提供 JSX 转换与 Fast Refresh(HMR)。如需扩展(如路径别名、代理 API),可在此文件按 Vite 官方约定追加resolve.alias或server.proxy。

TypeScript 工程引用

根 tsconfig.json 采用 Project References 方式管理两个子配置:

  • tsconfig.app.json:覆盖src应用代码。关键选项包括target: es2023、lib: ["ES2023", "DOM"]、moduleResolution: "bundler"、jsx: "react-jsx"、verbatimModuleSyntax: true(强制使用import type导入纯类型),并开启noUnusedLocals/noUnusedParameters/noFallthroughCasesInSwitch等严格检查,include: ["src"]。
  • tsconfig.node.json:覆盖vite.config.ts等 Node 侧文件,module: "nodenext"、types: ["node"]。

tsc -b会按引用关系依次增量构建两个子项目,这是npm run build能同时完成类型门禁的原因。

Oxlint 与 README 中的类型感知规则

data-table-app的 README 是 Vite 官方模板说明,重点讲解了 Oxlint 的扩展方式。Oxlint 是 Oxc 生态的高性能 lint 器,仓库lint脚本直接调用oxlint。官方建议:开发生产级应用时安装oxlint-tsgolint并在.oxlintrc.json中启用类型感知规则:

{ "$schema": "./node_modules/oxlint/configuration_schema.json", "plugins": ["react", "typescript", "oxc"], "options": { "typeAware": true }, "rules": { "react/rules-of-hooks": "error", "react/only-export-components": ["warn", { "allowConstantExport": true }] } }

其中react/rules-of-hooks强制遵守 Hooks 调用规则(顶层调用、不可条件调用),与本应用大量使用 Hooks 的写法直接相关;react/only-export-components约束组件文件只导出组件(允许常量导出),利于 Fast Refresh 生效。未开启typeAware时 Oxlint 仍可用,但无法执行需要类型信息的规则,这是模板明确提示的取舍。

数据层:类型定义与远程获取

User 类型

types/user.ts 定义了表格行数据的形状,company为嵌套对象,后续表格列即取自这些字段:

export interface User { id: number; name: string; email: string; phone: string; website: string; company: { name: string; }; }

数据服务

services/userService.ts 使用原生fetch请求公开占位 API:

const API_URL = "https://jsonplaceholder.typicode.com/users"; export const getUsers = async (): Promise<User[]> => { const response = await fetch(API_URL); if (!response.ok) { throw new Error("Failed to fetch users"); } return response.json(); };

要点:未使用 axios 等第三方库,直接以fetch完成;显式检查response.ok,失败时抛出统一错误信息,由上层捕获展示。实际项目中可将API_URL改为环境变量(如import.meta.env.VITE_API_URL)以适配不同环境。

组件实现:SearchBar、DataTable 与 Pagination

三个组件均为无状态(受控)纯展示组件,通过 props 接收数据与回调,符合 React 推荐的单向数据流。

SearchBar(受控搜索框)

components/SearchBar.tsx 是典型受控组件:value来自父组件,onChange把输入值上抛:

interface SearchBarProps { value: string; onChange: (value: string) => void; } export function SearchBar({ value, onChange }: SearchBarProps) { return ( <input type="text" placeholder="Search users" value={value} onChange={(e) => onChange(e.target.value)} /> ); }

DataTable(表格渲染)

components/DataTable.tsx 接收users: User[],渲染 5 列表头(Id / Name / Email / Phone / Company);列表为空时显示跨列(colSpan={5})的 "No users found" 占位行,避免空表格困惑:

{users.length === 0 ? ( <tr><td colSpan={5} className="empty">No users found</td></tr> ) : users.map((user) => ( <tr key={user.id}> <td>{user.id}</td> <td>{user.name}</td> <td>{user.email}</td> <td>{user.phone}</td> <td>{user.company.name}</td> </tr> ))}

使用user.id作为key是稳定且唯一的正确选择。

Pagination(分页控制)

components/Pagination.tsx 提供 Prev / Next 两个按钮与页码指示,并在边界禁用按钮:

interface PaginationProps { currentPage: number; totalPages: number; onPageChange: (page: number) => void; } <button disabled={currentPage === 1} onClick={() => onPageChange(currentPage - 1)}>Prev</button> <span>Page {currentPage} of {totalPages}</span> <button disabled={currentPage === totalPages} onClick={() => onPageChange(currentPage + 1)}>Next</button>

第一页时 Prev 禁用、最后一页时 Next 禁用,避免越界切换。

状态编排:App 组件中的数据流

src/App.tsx 是整个应用的状态中枢,同时管理四类状态:

  • users: User[]—— 异步拉取的全量数据;
  • search: string—— 搜索关键字;
  • currentPage: number—— 当前页码(从 1 开始);
  • loading: boolean、error: string—— 请求期状态。

异步取数

useEffect在挂载后调用loadUsers:先setLoading(true),成功则setUsers,失败则将Error实例的message写入错误状态,finally中复位 loading:

useEffect(() => { const loadUsers = async () => { try { setLoading(true); const users = await getUsers(); setUsers(users); } catch (error) { SetError(error instanceof Error ? error.message : "Something went wrong"); } finally { setLoading(false); } }; loadUsers(); }, []);

依赖数组为空表示仅在首次渲染执行一次。error instanceof Error的判断确保非标准错误对象也能安全兜底。注意:App.tsx中loading && <div>...</div>这类表达式因缺少return并不会真正渲染,实际加载/错误提示应放在 JSX 返回结构中实现。

搜索过滤:useMemo 缓存派生数据

过滤逻辑封装在useMemo中,依赖[search, users]:关键字先trim().toLowerCase()归一化,再对name、email、company.name三个字段做includes匹配:

const filteredUsers = useMemo(() => { const query = search.trim().toLowerCase(); if (!query) return users; return users.filter( (user) => user.name.includes(query) || user.email.includes(query) || user.company.name.includes(query), ); }, [search, users]);

useMemo保证只有search或users变化时才重新过滤,避免每次渲染都重复 O(n) 遍历,是面试中"何时使用useMemo"的标准答案示例。

分页切片

totalPages由Math.ceil(filteredUsers.length / PAGE_SIZE)计算,每页 5 条;当前页数据同样用useMemo切片,start = (currentPage - 1) * PAGE_SIZE:

const totalPages = Math.ceil(filteredUsers.length / PAGE_SIZE); const paginatedUsers = useMemo(() => { const start = (currentPage - 1) * PAGE_SIZE; return filteredUsers.slice(start, start + PAGE_SIZE); }, [currentPage, filteredUsers]);

交互联动

两个回调把子组件事件接入状态:

  • handleSearch:更新search的同时把currentPage重置为 1,保证搜索后总是从第一页看结果;
  • handlePageChange:更新页码。

搜索重置页码是分页应用最常见的坑点之一,这里的处理是正确范例。渲染时,只有totalPages > 1才显示分页器,避免单页场景出现无意义的控件。

入口与运行链路

src/main.tsx 是 React 挂载入口,使用 React 19 推荐的createRootAPI 并开启StrictMode:

createRoot(document.getElementById('root')!).render( <StrictMode> <App /> </StrictMode>, );

public/index.html 中<div id="root"></div>为挂载点,<script type="module" src="/src/main.tsx"></script>加载入口。整体调用链为:index.html → main.tsx → App.tsx → (SearchBar / DataTable / Pagination) → userService.getUsers(),数据自服务层流入状态,再经过滤、切片流向展示组件,链路清晰、易于追踪。

小结与延伸

data-table-app用约十个文件完整示范了现代 React 前端的最小闭环:异步数据获取(useEffect+fetch)、派生数据缓存(useMemo)、受控组件(SearchBar)、展示组件拆分(DataTable/Pagination)与状态联动(搜索重置页码)。配合 Vite 的极速 HMR、tsc -b类型门禁与 Oxlint 静态检查,可无痛扩展到真实管理后台。若想继续深化,可参考仓库中其他编码项目(如 coding-projects/todo-app、coding-projects/infinite-scroll-app)对比不同的数据流组织方式,也可将搜索改为防抖、分页改为服务端分页作为进阶练习。

  • 前端
  • 教程
  • 文档

【免费下载链接】reactjs-interview-questions

List of top 500 ReactJS Interview Questions & Answers....Coding exercise questions are coming soon!!

项目地址:https://gitcode.com/GitHub_Trending/re/reactjs-interview-questions
点击查看免费下载

相关推荐

上一篇:5分钟上手LaspVfx:Unity音频驱动VFX的快速入门教程
下一篇:从0到1掌握Kubernetes生态利器:Contrib组件实战指南

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询