react--项目搭建&ant design组件库应用&高频Hook
项目搭建
1 | npm create vite@latest nie-react-app -- --template react-ts (一定要加-ts,不然默认用js,后面再改ts很麻烦没成功,我重新创建了一个) |
目录(初版)
1 | src/ |
main.tsx:
1 | createRoot(document.getElementById('root')!).render( |
<StrictMode>:React 严格模式(react18开发环境增强工具):一个「无视觉效果的包装组件」,仅在开发环境生效,生产环境会自动忽略
app.tsx
1 | import React from "react"; |
路由配置
router/index.tsx
1 |
|
全局布局配置
我希望给整个项目添加一个Header,包含所有页面的导航:
- Header组件
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44Header.tsx:
const navItems = [
{ path: "/dashboard", title: "Dashboard" },
{ path: "/usermanagement", title: "UserManagement" },
{ path: "/pdftopic", title: "PdfToPic" },
{
path: "/documentmanagement",
title: "DocumentManagement",
}, {
path: "/checklist",
title: "CheckList",
}
];
const Header = () => {
const navigate = useNavigate();
const location = useLocation();
const handleNavClick = (path: string) => {
navigate(path);
};
return (
<div style={{ padding: "16px", borderBottom: "1px solid #e8e8e8" }}>
<Space size="middle">
{navItems.map((item) => (
<span
style = {{
cursor: "pointer",
color: location.pathname === item.path ? "#1890ff" : "inherit",
}}
key={item.path}
onClick={() => handleNavClick(item.path)}
>
{item.title}
</span>
))}
</Space>
</div>
);
};
export default Header; - 使用Layout组件进行全局布局
<Outlet />:路由出口
来自 react-router-dom 的组件,作用是占位符:
当访问不同路由(如 /homepage、/usermanagement)时,<Outlet />会被对应的页面组件(如 HomePage、UserManagement)替换
访问 /homepage 时,<Outlet />会渲染 HomePage 组件;访问 /usermanagement 时,会渲染 UserManagement 组件
1 | const RootLayout = () => { |
- 路由配置
把Layout组件作为父级路径,希望使用这个布局的页面作为它的children1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24const RouterMap: NieRouteMap[] = [
{
path: "/",
auth: 0,
title: "Roothome",
key: "roothome",
element: loadElement(<Layout />),
children: [
{
path: "/homepage",
auth: 0,
title: "Homepage",
key: "homepage",
parentpath: "/",
element: loadElement(<HomePage />),
},{
path: "/checklist",
auth: 0,
title: "CheckList",
key: "checklist",
parentpath: "/",
element: loadElement(<NieChecklist />),
}
]}]1

store配置(初始版)
- 安装依赖
1
2
3
4npm install react-redux redux
npm install react-redux /toolkit
页面组件:
import (useDispatch, useSelector) from "react-redux"; - 目录
1
2
3
4
5src/
├── store/
│ └── checklist/
│ │ └── checklistSlice.ts
│ └── index.tsx - 创建store
注意:在Redux Toolkit中,如果我们直接返回一个新的状态,它会替换整个状态。而如果我们不返回,而是修改state,那么Immer会帮我们生成新的状态
简单新建一个checklistStore,我开始在action里return state,这样做不好,AI帮我更正了代码:
checklistSlice1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48import { createSlice } from '@reduxjs/toolkit'
const initialState = {
finallyShowCheckboxList: [],
basicInformation: { },
nieChecklistOptions: [],
}
const NieChecklistSlice = createSlice({
name: 'Checklist',
initialState,
reducers: {
initChecklistInfo(state) {
// 直接重置状态,不需要返回
state.finallyShowCheckboxList = []
state.basicInformation = {}
state.nieChecklistOptions = []
},
handleChangeBasicInformationValues(state, { payload }) {
// 合并更新基本信息
state.basicInformation = { ...state.basicInformation, ...payload }
console.log('state.basicInformation:', state.basicInformation)
// 不需要 return state
},
handleChangeBasicInformation(state, { payload }) {
// 修正:直接替换整个 basicInformation 对象
state.basicInformation = payload
// 不需要 return state
},
handleChangeFinallyShowCheckboxList(state, { payload }) {
state.finallyShowCheckboxList = payload
},
// 新增:更新选项列表的 reducer
handleChangeNieChecklistOptions(state, { payload }) {
state.nieChecklistOptions = payload
}
}
})
export const {
initChecklistInfo,
handleChangeBasicInformationValues,
handleChangeFinallyShowCheckboxList,
handleChangeBasicInformation,
handleChangeNieChecklistOptions
} = NieChecklistSlice.actions
export default NieChecklistSlice.reducer
store缓存->浏览器缓存
安装依赖npm install redux react-redux redux-persist
store下的index.tsx
1 | // store/index.js |

入口文件main.ts修改
1 | import { StrictMode } from "react"; // React 严格模式,帮助发现代码问题 |
在组件使用store
最基本导入
1 | import React from "react"; |
零碎小册子
- 数据存取:页面数据变->放缓存;初次进来->从缓存拿数据放页面
取数据:整个checklist包含了多个组件,每个组件在缓存里对应一个对象,用useEffect监听缓存具体对象
store:1
2
3
4
5
6
7
8const initialState = {
allChecklistValue:{
basicInformation: {},
hobbyInformation: {},
},
nieChecklistOptions: [],
}1
2
3
4
5
6
7
8
9
10const MyChecklistStore = useSelector((state: any) => state.Checklist);
import { useEffect } from "react";
const basicInfoFormInit = () => {
if(MyChecklistStore.allChecklistValue.basicInfo){
basicInfoForm.setFieldsValue(MyChecklistStore.allChecklistValue.basicInfo)
}
}
uesEffect(() => {
basicInfoFormInit()
},[MyChecklistStore.allChecklistValue.basicInfo]) - 数据判断:取对象里的对象
MyChecklistStore.allChecklistValue.basicInfo;判断对象keyif('key' in obj){};判断数组是否有某个值if(arr.includes(value)){} - 如果一个dropdown值会导致其他字段值disable,比如是form.item->在onchange里监听->判断数据变化的key是否为特殊字段的name->form.getFieldValue(name)获取值->判断值是否为特殊值->dispatch(action({key1:’’,,key2:’’,key3:’’}))
ant design组件库应用————实现Form表单联动(checklist)
记录我用到的ant design组件和api
Form表单:
onFieldsChange方法有坑,很容易触发三次,因为他不是单一值变化触发,校验触发也会触发,最好用onValuesChange代替
1 | <Form form={basicInfo}></Form> |
日期选择器DatePicker:
日期数据格式和转换
DatePicker要求数据格式是dayjs对象,string->dayjs:dayjs(string)
但是缓存存储数据要转换为string,dayjs->string:data.tostring()
自定义日期展示类型:format=”YYYY-MM-DD”
我的代码
存取日期时进行格式转换
1 | //从页面取日期到store,string->dayjs |
DatePickerA变->DatePickerB自动赋值
form.setFieldsValue({ "birthdayNextYear": nextYearDate });
1 | const handleBssicFormFieldsChange = (changedFields: any, allFields: any) => { |
日期限定范围
出生日期不能选则未来
1 | <DatePicker |
form.item的可编辑disable&必填&hidden受其他item值控制:
受checkbox值控制(单一值控制):

Form.item : rules={[{ required: 条件 }]} hidden={条件} label={isFruitCard ? 'Fruit card ' : ' Others'}
组件上: disabled={条件}
我的代码
1 | <Row gutter={[32, 16]}> |
受Select值控制(多个值控制):
一个Select组件的多个选项都可以值另一个item变为必填:
一定要有||[],不然初次渲染会报错,或者在.getFieldValue(‘favoriteFruit’)前加问号
1 | <Form.Item |
<Form.Item
Checkbox:(message组件静态方法使用失败)
三个Checkbox有一个选中则弹消息(message组件静态方法使用失败)
- 完整代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26const handleBssicFormChange = (changedValues: any, allValues: any) => {
...
//三个checkbox选中其一则弹提示消息
const checkboxFields = [
"sleepBeforTwelve",
"drinkWater",
"eatApple"
];
//判断changeValues中是否有checkbox字段
const isCheckboxFieldsChange = checkboxFields.some((field) =>
Object.hasOwn(changedValues, field)
);
if (isCheckboxFieldsChange) {
//再判断是选中还是取消选中
let ifCheckboxTrue = Object.values(changedValues).some(value => value === true)
console.log("ifCheckboxTrue", ifCheckboxTrue);
if (ifCheckboxTrue) {
console.log('进来了')
setTimeout(() => {
message.warning("继续保持哦");
}, 100);
}
}
}; - message组件静态方法使用失败:原因:React18的兼容性与调用时机,应将message的调用放在事件处理函数(如onClick)、生命周期钩子或useEffect中
1
2
3
4
5
6
7
8
9
10
11
12//我开始的代码,能走进来但是始终不会触发消息弹窗,奇怪的是公司代码我这样写就可以
const handleBssicFormChange = (changedValues: any, allValues: any) => {
...
if (isCheckboxFieldsChange) {
//再判断是选中还是取消选中
let ifCheckboxTrue = Object.values(changedValues).some(value => value === true)
console.log("ifCheckboxTrue", ifCheckboxTrue);
if (ifCheckboxTrue) {
message.warning("继续保持哦");
}
}
}
然后我这样改,依然报错:原因:在普通的JavaScript函数中使用了React Hook(useEffect),这是不允许的。React Hooks只能在函数组件的最顶层或其他Hooks中调用1
2
3
4
5
6
7
8
9
10
11
12
13const handleBssicFormChange = (changedValues: any, allValues: any) => {
...
if (isCheckboxFieldsChange) {
//再判断是选中还是取消选中
let ifCheckboxTrue = Object.values(changedValues).some(value => value === true)
console.log("ifCheckboxTrue", ifCheckboxTrue);
useEffect(() => {
message.warning("继续保持哦");
}, [ifCheckboxTrue === true]);
}
}
我还是觉得我最初的代码没问题,AI让我加延迟,还是没用1
2
3
4
5
6
7
8
9
10
11if (isCheckboxFieldsChange) {
//再判断是选中还是取消选中
let ifCheckboxTrue = Object.values(changedValues).some(value => value === true)
console.log("ifCheckboxTrue", ifCheckboxTrue);
if (ifCheckboxTrue) {
console.log('进来了')
setTimeout(() => {
message.warning("继续保持哦");
}, 100);
}
}
Select多个选项中有三个选项只可选其一
Select组件选择的选项是一个数组
1 | const [fruitTypeOptions,setFruitTypeOptions] = useState(originalFruitOptions) |
条件判断
- checkbox勾选->控制其他input的disable

官方文档:
Form.Item 默认绑定值属性到 value 上,而 Switch、Checkbox 等组件的值属性为 checked。你可以通过 valuePropName 来修改绑定的值属性<Form.Item label=" " name="isLikeNovel" valuePropName="checked">
组件库应用–可编辑Table(checklist)
相关ts语法
type CompanyTableColumnTypes = Exclude<TableProps<NBChecklistCoverageAgeTableDataType>['columns'], undefined>
从 Ant Design 的 Table 组件的 columns 属性中,提取出 “非 undefined 的列配置类型”,用于确保你定义的列不会是 undefined
TableProps
一个泛型类型,一个 Table 组件的所有属性(props)类型,其中 NBChecklistCoverageAgeTableDataType 是你表格数据的类型(比如每行的数据结构)TableProps<...>['columns']
取出 TableProps 中的 columns 字段,在 Ant Design 中,columns 是一个可选的数组,类型通常是: ColumnProps<NBChecklistCoverageAgeTableDataType>[] | undefinedExclude<T, U> `是 TypeScript 的一个内置工具类型,从类型 T 中剔除 U 类型 所以: Exclude<ColumnProps<...>[] | undefined, undefined>
→ 等价于: ColumnProps<...>[]
把 undefined 剔除后,只剩下数组类型
所以最终 CompanyTableColumnTypes 就是 一个合法的、非 undefined 的表格列配置数组类型
为什么这样做?防止你在定义列时,不小心写成 undefined。确保你传给 Table 的 columns 是一个真正的列数组,而不是 undefined。提高类型安全性,避免运行时的错误。
1 | const coverageAgeTableColumns: (CoverageAgeTableColumnTypes[number] & { |
CoverageAgeTableColumnTypes[number]CoverageAgeTableColumnTypes 是一个联合类型(通常是 ColumnProps<…>[] 的类型推断)。number 索引表示:从这个联合类型中取出每一个可能的列类型。作用:确保你定义的每一列,都符合预设的列结构之一。
举例:
1 | type CoverageAgeTableColumnTypes = [ |
那么 CoverageAgeTableColumnTypes[number] 就是:
1 | { title: string; dataIndex: 'productType'; key: 'productType' } | |
& { editable?: boolean; dataIndex: string }强制所有列都必须有 dataIndex,且可选支持 editable。
完整的可编辑Tables
条件渲染
1 | { value ? <div>sth</div> : null} |
响应拦截器–节流防抖
ant design草稿本
Form
通过Form.useForm() 创建并绑定表单实例,作用是提供对表单的直接控制能力,表单实例提供了一系列方法,让你可以主动读取、设置或清空表单数据,而无需通过 onChange 手动维护状态
1
<Form baiscform={form}></Form>
form两个重要监听方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14form.getFieldsValue() //返回表单所有数据
form.getFieldsValue(['name1','name2']) //返回[[name1,key1],[name2,key2]]
const handleChangeForm = (changedFields,allFields)=>{
switch(changedFields[0].name[0]){
case 'checkbox':
if(changedFields[0].value){
dispatch(handleChangeSelectboxList[...selectedCheckoxList,changedFields[0].name[0]])
}
break
defult:
break
}
}
<Form nform={form} onFieldsChange={handleChangeForm}></Form>onValuesChange 监听表单值的变化(最终数据),onFieldsChange 监听表单字段状态的变化(字段信息)
- onValuesChange:监听表单值变化
触发时机:表单字段的 value 发生改变时触发(如输入框输入文字、复选框勾选 / 取消)。
参数说明:
changedValues:仅包含本次变化的字段键值对(如 { name: “张三” })。
allValues:表单当前所有字段的完整值(如 { name: “张三”, age: 20, isLikeNovel: true })。
使用场景:
需根据字段值更新状态(如同步表单值到 Redux Store)。
基于值的简单联动(如勾选 isLikeNovel 后显示相关输入框)。
示例:你的代码中同步表单值到 basicInformation,仅需关注变化的字段,无需处理字段元信息。 - onFieldsChange:监听表单字段状态变化 值变化的同时需要对name进行校验用这个方法
触发时机:表单字段的值或状态发生改变时触发(值变化、禁用状态切换、校验状态变化等)。
参数说明:
changedFields:本次变化的字段数组,每个元素包含字段的 name、value、errors、warnings、disabled 等元信息(如 [{ name: “character”, value: “INFP”, disabled: false }])。
allFields:所有字段的完整元信息数组
- onValuesChange:监听表单值变化
form.item重新渲染
form.item是受控组件,它的渲染逻辑以来form的状态
如果form.itemA的受到form.itemB的影响:1
2
3
4
5
6
7
8
9
10
11
12
13
14<Col span={8}>
<Form.Item
shouldUpdate={(preValue, curValue) =>
preValue.isLikeNovel !== curValue.isLikeNovel
}
noStyle
>
{() => (
<Form.Item label="最喜欢的小说" name="likeNovel">
<Input disabled={!basicForm.getFieldValue("isLikeNovel")} />
</Form.Item>
)}
</Form.Item>
</Col>labelInValue
把每个选项的label包装到 value 中,会把 Select 的 value 类型从 string 变为 {value: string, label: ReactNode} 的格式
默认情况下 onChange 里只能拿到 value,如果需要拿到选中的节点文本 label,可以使用 labelInValue 属性,如果没有它,选中之后 onChange 捕获的 value 没有值
Table
- filteredValue 筛选的受控属性,外界可用此控制列的筛选状态,值为已筛选的 value 数组 string []
- pagination 分页器配置项
const navigate = useNavigate()- 是 React Router 中的一个 Hook,用于在 React 应用中实现编程式导航。编程式导航允许你在代码中控制导航行为,而不是通过点击链接或表单提交来触发导航。
- Table–scroll滚动条配置
- scrollToFirstRowOnChange属性:当分页、排序、筛选变化后是否滚动到表格顶部(boolean)
- 控制Table是否可选
rowSelection={{type: 'checkbox'|'raido'}}
在定义表格列时,如果需要扩展功能(如添加 “编辑”、”查看” 按钮),可以在 render 函数中返回包含多个按钮的容器(如 Ant Design 的 Space 组件)
控制Table是否可选 示例
1 | // 表格列配置 |
InputNumber 数字输入框
- formatter展示值规则
formatter={dataIndex === ‘claimPaid’ ? Aformatter : Bformatter} - parser存值规则(存储的数据,要传给后端的数据的转换规则)
parser={dataIndex === ‘claimPaid’ ? Aparser : Bparser} // 存值规则(存储的数据,要传给后端的数据的转换规则)
/>
Upload
onChange 事件:上传中、完成、失败都会调用这个函数
当删除时候,当前文件的状态改变,也会触发它
它的两个参数 file 和 fileList
file 是当前操作文件的详细信息,当文件被删除时,操作的是被删除文件,所以 list 的数据是被删除文件对象
fileList 是当前文件列表数组,删除当前上传 / 预上传的文件 ->fileList 会对应删除文件
时间选择器
- allowClear 属性用于控制日期选择器是否显示清除按钮。
当设置为 true 时,会自动添加一个默认的清除按钮。
当设置为一个对象时,可以通过 clearIcon 属性来自定义清除按钮的图标 - disabledDate 不可选择的日期
- shouldUpdate 属性用于控制表单项在值更新时的行为,通过比较更新前后的表单值来决定是否更新
<Form.Item shouldUpdate={(prevValues, curValues) => prevValues.updatedYear === curValues.updatedYear}>
updatedYear 的值发生变化时,表单项会更新
当 shouldUpdate 为 true 时,Form 的任意变化都会使该 Form.Item 重新渲染。这对于自定义渲染一些区域十分有帮助,要注意 Form.Item 里包裹的子组件必须由函数返回,否则 shouldUpdate 不会起作用当 shouldUpdate 为方法时,表单的每次数值更新都会调用该方法,提供原先的值与当前的值以供你比较是否需要更新updatedYear: dayjs().year().toString(): 获取当前日期和时间的年份转字符串onFinish 属性:提交表单且数据验证成功后回调事件onFieldsChange 属性:字段更新时触发回调事件1
2
3<Form.Item label="Updated Year" name="updatedYear">
<Select allowClear options={updatedYearOptions} />
</Form.Item> - 转换:dayjs=->string string->dayjs
树形控件
React Hook
useEffect 副作用与依赖类型
在函数组件中执行副作用操作
1 | import { useEffect } from 'react'; |
依赖项数组 [] 的三种情况:
- 不提供:Effect 在每次渲染后都会执行。
- 空数组 []:Effect 只在组件挂载后执行一次
- 有依赖的数组 [a, b]:Effect 在组件挂载后和 a 或 b 发生变化后执行
- 整个缓存:缓存的引用变化时触发
清理函数用于避免内存泄漏(如取消订阅、清除定时器)
useState 状态管理
在函数组件内部管理局部状态,是React 数据流的核心,状态的更新会触发组件的重新渲染
1 | import { useState } from 'react'; |
状态更新可能是异步的,React会对多次setState 进行批处理以提高性能
如果新状态与旧状态相同(通过 Object.is 比较),React 将跳过这次渲染,是一种优化
useRef 值存储
是 React 提供的一个钩子,用于在函数组件中创建对 DOM 元素或普通 JavaScript 值的引用。这个引用在组件的整个生命周期内保持不变
存储值(不引发组件重新渲染):useRef 可以存储一个值,在更新时,该值不会触发组件重新渲染,且该值可以在组件的整个生命周期中保存
实现可变的 “数据容器”:useRef 内部使用的是一个 “可变的容器”,这个容器不会随着组件更新重新初始化
useRef 的核心特性
useRef 返回一个具有 current 属性的对象:{current: initialValue}
current 的值可以任意修改,但修改不会触发组件重新渲染
生命周期内保持稳定的引用:useRef 创建的引用在整个组件生命周期中保持不变
它既不会随着组件更新丢失,也不会重新初始化
更新 current 属性的值不会让组件重新渲染,而使用 useState 更新状态的值会导致重新渲染
注意:useRef 不应用于需要自动触发渲染的数据存储。对于需要反映到 UI 的数据,应该使用 useState
useLocation
useLocation () 是 React Router 中的一个 Hook,用于获取当前的路由位置对象
这个对象包含以下属性:
pathname:当前路径的名称
search:URL 中的查询参数部分
hash:URL 中的哈希部分
key:代表此次导航
state:传递给当前路径的状态数据,里面的数据是路由跳转时 state 传值来的
eg1
1 | //跳转传参 |
eg2
1 | navigate('/melon', { |
1 | const hyperLink = useLocation().state?.melonLink; |
useImperativeHandle 子传父
让父组件能够调用子组件的特定方法,而不是直接访问子组件的整个实例
子组件
1 | useImperativeHandle( |
父组件
1 | const checklistRef = useRef(null) |
useMemo & useCallback
缓存函数和计算结果,避免不必要的重新创建和重渲染
useRef DOM引用与可变值0容器
可以存放任何会变化的值,但其值的改变不会触发组件重新渲染
1 | import { useRef, useEffect } from 'react'; |
useContext 跨组件数据传递
useReducer
1 | // 在全局作用域定义 |
1 | // 在全局作用域定义 |





