以下集成内容仅对组件封装思想进行说明,如需进行代码对照,可参考目录下 react19_ts 项目内实际代码,文档与代码会在git上持续补充
git仓库地址:https://gitee.com/xiaoli-account/react19_ts什么是React组件?为什么使用React组件?React组件怎么通信交互?
- • 我首先将我的疑惑整理一下,然后再去理解他、学习他、掌控他、最后去超越他(梦想还是要有的万一成真了呢)
先去读文档
https://react.docschina.org/learn/passing-props-to-a-component
https://react.docschina.org/learn/passing-data-deeply-with-context
https://www.npmjs.com/package/mitt
https://zustand.docs.pmnd.rs/learn/getting-started/introduction
ref实例通信,配合useImperativeHandle暴露指定方法
https://react.docschina.org/learn/manipulating-the-dom-with-refs#best-practices-for-dom-manipulation-with-refs
什么是组件?
- • 我理解react中的组件就是变量,一个高级变量,可以让你随便揉捏的iframe变量
• 优势
- • 他下限高(因为与html编写页面思想不同)、上限也高,掌控住react组件化思想,那么我们就可以使用js来写代码,js的上限就是react的上限
- • 无规矩不成方圆,一旦项目乱写乱封组件,滥用react组件思想,就极易写出屎山代码,导致难以维护只能重构,对开发人员代码规范要求高
为什么使用组件?
- • react特性就是通过tsx/jsx用jquery的方式写html,本身就具备了高度灵活性,高度可定制性
- • 这个时候将页面内容拆分为组件,将逻辑聚合在组件内部,可以提升代码的可读性、维护时也更简单
组件怎么封装?
组件怎么通信交互?
- • 1、props/callback传参交互 与vue中props/emit效果相似
- • 注:在使用组件时避免不了会想到vue的v-slot插槽功能,在react中实现插槽功能,就是通过prop传参,在子组件中将对应的变量进行处理即可,插槽参数回传=callback(params)的参数回调
- • 2、Context API 与 vue中的inject注入相似
- • 3、事件总线mitt三方库,这个在vue3_ts项目中也集成用到了
- • 4、全局状态管理【Redux、Zustand】与vue中的pinia使用相似
- • 5、ref实例通信配合useImperativeHandle暴露指定方法 与vue中的refs/defineExpose相似
props/callback传参交互
// src/pages/examples/component-example/props-callback/index.tsxconstPropsCallbackExample: React.FC = () => {const [data, setData] = useState<DataRecord[]>(mockData);// 搜索 — SearchBar 通过 onSearch callback 将搜索条件传回consthandleSearch = (values: any) => setData(/* 过滤逻辑 */);return<SearchBaronSearch={handleSearch} />;};// src/pages/examples/component-example/props-callback/components/SearchBar.tsxinterfaceSearchBarProps {onSearch: (values: { name?: string; status?: string }) =>void;}constSearchBar: React.FC<SearchBarProps> = ({ onSearch }) => {const [form] = Form.useForm();return (<Formform={form}onFinish={() => onSearch(form.getFieldsValue())}><ButtonhtmlType="submit">查询</Button></Form> );};
Context API上下文,子孙组件通信
// src/pages/examples/component-example/context-api/context-api/DataContext.tsxconstDataContext = createContext<DataContextType | null>(null);exportconstuseDataContext = () => useContext(DataContext)!;exportconstDataProvider: React.FC<{ children: ReactNode }> = ({ children }) => {const [data, setData] = useState<DataRecord[]>(mockData);constsearch = (values: any) => setData(/* 过滤逻辑 */);return<DataContext.Providervalue={{data, search }}>{children}</DataContext.Provider>;};// src/pages/examples/component-example/context-api/components/SearchBar.tsxconstSearchBar: React.FC = () => {// 无需 props,直接通过 useDataContext 获取数据和方法const { search } = useDataContext();const [form] = Form.useForm();return (<Formform={form}onFinish={() => search(form.getFieldsValue())}><ButtonhtmlType="submit">查询</Button></Form> );};
事件总线mitt三方库
// src/pages/examples/component-example/event-bus/event-bus/use-event-bus.tsimport mitt from"mitt";exportconst eventBus = mitt<{ "data:search": any }>();// src/pages/examples/component-example/event-bus/components/SearchBar.tsxconstSearchBar: React.FC = () => {const [form] = Form.useForm();// 不接收 props,搜索操作直接通过 eventBus.emit 广播return (<Formform={form}onFinish={() => eventBus.emit("data:search", form.getFieldsValue())}><ButtonhtmlType="submit">查询</Button></Form> );};// src/pages/examples/component-example/event-bus/components/DataTable.tsxconstDataTable: React.FC = () => {const [data, setData] = useState<DataRecord[]>(mockData);useEffect(() => {constonSearch = (filters: any) => setData(/* 过滤更新 */); eventBus.on("data:search", onSearch); // 订阅事件return() => eventBus.off("data:search", onSearch); // 必须取消监听防泄漏 }, []);// ... 渲染表格};
全局状态管理【Redux、Zustand】
// src/pages/examples/component-example/zustand/store/use-data-store.tsimport { create } from"zustand";exportconst useDataStore = create<DataStoreState>((set) => ({items: mockData,search: (filters) =>set({ items: /* 过滤更新 */ }),}));// src/pages/examples/component-example/zustand/components/SearchBar.tsxconstSearchBar: React.FC = () => {const search = useDataStore((s) => s.search); // 按需订阅 Storeconst [form] = Form.useForm();return (<Formform={form}onFinish={() => search(form.getFieldsValue())}><ButtonhtmlType="submit">查询</Button></Form> );};
ref实例通信
// src/pages/examples/component-example/ref-example/components/SearchForm.tsxexportinterfaceSearchFormRef { focus: () =>void; }constSearchForm = forwardRef((props: any, ref: Ref<SearchFormRef>) => {const inputRef = useRef<any>(null);// 只暴露指定方法给父组件(类似 Vue defineExpose)useImperativeHandle(ref, () => ({ focus: () => inputRef.current?.focus() }));return<Inputref={inputRef}placeholder="请输入名称" />;});// src/pages/examples/component-example/ref-example/index.tsxconstRefExample: React.FC = () => {// 创建 ref 指向子组件实例const searchFormRef = useRef<SearchFormRef>(null);// 通过 ref 调用子组件暴露的方法consthandleFocusSearch = () => searchFormRef.current?.focus(); return (<><ButtononClick={handleFocusSearch}>聚焦搜索框</Button><SearchFormref={searchFormRef}onSearch={handleSearch} /></> );};
组件示例页面目录
component-example/├── index.tsx # 主入口(Tabs 中转)├── types.ts # 共用数据类型 & 模拟数据├── readme.md # 文档│├── props-callback/ # 1. Props/Callback 通信│ ├── index.tsx # 父组件(管理状态)│ └── components/│ ├── SearchBar.tsx # 子组件:搜索栏│ ├── DataTable.tsx # 子组件:数据表格│ └── EditModal.tsx # 子组件:编辑弹窗│├── context-api/ # 2. Context API 通信│ ├── index.tsx # 入口(DataProvider 包裹)│ ├── context-api/ # 抽离出来的上下文数据与│ │ └── DataContext.ts # Context + Provider + Hook│ └── components/│ ├── SearchBar.tsx # 消费 Context│ └── DataTable.tsx # 消费 Context│├── event-bus/ # 3. 事件总线 (mitt) 通信│ ├── index.tsx # 入口(协调弹窗 + 发布事件)│ ├── eventBus/ │ │ └── event-bus.ts # mitt 实例定义│ └── components/│ ├── SearchBar.tsx # emit 搜索/重置事件│ └── DataTable.tsx # on 监听所有数据事件│├── zustand/ # 4. Zustand 全局状态管理│ ├── index.tsx # 入口(订阅 Store)│ ├── store/ # Zustand Store 定义│ │ └── use-data-store.ts│ └── components/│ ├── SearchBar.tsx # 按需订阅 Store│ └── DataTable.tsx # 按需订阅 Store│└── ref-example/ # 5. Ref 实例通信 ├── index.tsx # 父组件(通过 ref 调用子组件方法) └── components/ ├── SearchForm.tsx # forwardRef + useImperativeHandle └── DataTable.tsx # forwardRef + useImperativeHandle
好了好了先这样,先学会写组件,在学怎么玩组件
💪💪💪💪