如何为useParamsData Hook自动推导不同组件initData的类型?
问题描述
当不同组件向useParamsData Hook传入结构不同的initData时,能否为Hook的参数传递类型,并将其指定为params的类型?
目前的手动方案需要为每个组件的initData定义类型,再手动添加联合类型到Hook的参数中,新增组件时十分繁琐,希望替代这种方案。
useParamsData Hook用于在事件触发时将各类数据存入params,避免重复编写change/onclick等逻辑。已知useState可通过泛型指定初始数据类型,但在Jotai Atom中难以实现,特此寻求解决方案。
原始代码示例
useParams.ts
import { useEffect, useState } from 'react'; export const useParamsData = (initData) => { const [params, setChangeParams] = useState({}); useEffect(() => { setChangeParams(initData); }, []); return { params, setChangeParams, }; };
ComponentA.tsx
import { useState } from 'react'; import { useParamsData } from './useParamsData'; import './style.css'; export const ComponentA = () => { const initData = { age: 0, name: 'jhon', county: '', }; const { params, setChangeParams } = useParamsData(initData); return ( <div> <p>Start editing to see some magic happen :)</p> </div> ); };
ComponentB.tsx
import { useState } from 'react'; import { useParamsData } from './useParamsData'; import './style.css'; export const ComponentB = () => { const initData = { category: 'All', status: 'All', type: 'All', module: 'All', keword: '', startDate: '', endDate: '', }; const { params, setChangeParams } = useParamsData(initData); return ( <div> <p>Start editing to see some magic happen :)</p> </div> ); };
需替代的手动方案
--- useParams.ts--- import { useEffect, useState } from 'react'; type A = { age: string name: string county: string, } type B = { category: string status: string type: string module: string keword : string startDate: string } export const useParamsData = (initData : A | B) => { const [params, setChangeParams] = useState({}); useEffect(() => { setChangeParams(initData); }, []); return { params, setChangeParams, }; };
解决方案:用泛型实现动态类型推导
React 版本
给useParamsData添加泛型,让TypeScript自动推导initData的类型,无需手动维护联合类型:
import { useState } from 'react'; export const useParamsData = <T extends Record<string, unknown>>(initData: T) => { // 直接用initData初始化useState,泛型T自动绑定类型 const [params, setChangeParams] = useState<T>(initData); // 原代码的useEffect多余,因为useState已用initData初始化 return { params, setChangeParams }; };
组件调用时,TypeScript会自动推导params的类型:
- ComponentA中
params类型为{ age: number; name: string; county: string } - ComponentB中
params类型为{ category: string; status: string; type: string; module: string; keword: string; startDate: string; endDate: string }
Jotai Atom 版本
通过泛型函数生成对应类型的Atom,解决Jotai中动态类型的问题:
import { atom, useAtom } from 'jotai'; // 泛型函数生成指定类型的Atom export const createParamsAtom = <T extends Record<string, unknown>>(initData: T) => { return atom<T>(initData); }; // 组件内使用示例 export const ComponentA = () => { const initData = { age: 0, name: 'jhon', county: '' }; const paramsAtom = createParamsAtom(initData); const [params, setParams] = useAtom(paramsAtom); return <div>{/* 组件内容 */}</div>; };
如果需要跨组件共享Atom,可通过类型断言指定具体类型:
import { atom, useAtom } from 'jotai'; // 基础共享Atom export const paramsAtom = atom<Record<string, unknown>>({}); // 组件内使用时指定类型 export const ComponentA = () => { type ParamsType = { age: number; name: string; county: string }; const [params, setParams] = useAtom<ParamsType>(paramsAtom); setParams({ age: 25, name: 'John', county: 'USA' }); return <div>{params.name}</div>; };
内容的提问来源于stack exchange,提问作者김찬영
相关产品推荐
相关产品推荐

