如何从自定义Hook向组件传递数据?类型不匹配问题排查
解决TypeScript类型不匹配错误及代码优化
问题根源
useTable返回的data类型是Data | undefined(Data是键为分类名、值为DataTable[]的对象),但setData1需要的是DataTable[] | undefined,直接赋值导致类型不兼容。Settings组件中解构useTable返回值时,多取了不存在的checkall和changeDatabase,不符合useTable的返回结构。useTable内部更新data时未使用函数式更新,存在闭包导致的旧值引用问题。filter回调的参数类型错误,误将单个数据项写成数组类型。
修复步骤
修正
useTable的返回类型与数据更新逻辑- 给
useTable明确返回类型,避免TS自动推断出错。 - 使用函数式更新
setData,确保获取最新的data状态。 - 修正
filter的参数类型,response是DataTable[],回调的第一个参数是单个DataTable项。
- 给
调整
Settings组件的解构与赋值逻辑- 只解构
useTable返回的两个值:data和columns。 - 从
data中取出对应分类的DataTable[](比如传入的"new"分类),再赋值给data1。 - 给
useEffect添加正确的依赖项,确保数据更新时能触发赋值。
- 只解构
优化
useTable的参数使用- 可利用传入的
actualcategory参数,让Hook直接返回对应分类的数据,简化组件逻辑。
- 可利用传入的
修正后的完整代码
interface DataTable { [id: string | number]: string | number; } interface Data { [category: string]: DataTable[]; } interface Column { col: { title: string; disp: boolean; }; } const urls: string[] = [ "https://jsonplaceholder.typicode.com/posts", "https://jsonplaceholder.typicode.com/comments", "https://jsonplaceholder.typicode.com/albums", "https://jsonplaceholder.typicode.com/photos", "https://jsonplaceholder.typicode.com/todos", ]; // 明确Hook的返回类型 const useTable = (idurl: number, actualcategory: string): [Data | undefined, Column[] | undefined] => { const [data, setData] = useState<Data>(); const [columns, setColumns] = useState<Column[]>(); const loadDatabase = () => { fetch(urls[idurl]) .then((response) => response.json()) .then((response: DataTable[]) => { // 使用函数式更新获取最新状态 setData(prevData => ({ ...prevData, new: response.filter((t: DataTable, i: number) => i > 50 && i < 100), removed: response.filter((t: DataTable, i: number) => i > 100 && i < 150), postponed: response.filter((t: DataTable, i: number) => i > 50 && i < 100), })); if (response.length > 0) { const objcolumn: Column[] = Object.keys(response[0]).map(t => ({ col: { title: t, disp: true } })); setColumns(objcolumn); } }); }; useEffect(() => { loadDatabase(); }, []); return [data, columns]; }; export { useTable }; const Settings = () => { // 只解构存在的返回值 const [data, columns] = useTable(1, "new"); const [data1, setData1] = useState<DataTable[]>(); useEffect(() => { // 取出对应分类的DataTable数组 if (data) { setData1(data["new"]); } }, [data]); // 依赖data,确保数据更新时触发 return <>></>; };
额外优化建议
如果希望useTable直接返回指定分类的数据,可以修改Hook逻辑,进一步简化组件:
const useTable = (idurl: number, actualcategory: string): [DataTable[] | undefined, Column[] | undefined] => { const [categoryData, setCategoryData] = useState<DataTable[]>(); const [columns, setColumns] = useState<Column[]>(); const loadDatabase = () => { fetch(urls[idurl]) .then((response) => response.json()) .then((response: DataTable[]) => { // 根据分类筛选对应数据 let targetData: DataTable[] = []; switch(actualcategory) { case "new": targetData = response.filter((t, i) => i > 50 && i < 100); break; case "removed": targetData = response.filter((t, i) => i > 100 && i < 150); break; case "postponed": targetData = response.filter((t, i) => i > 50 && i < 100); break; default: targetData = []; } setCategoryData(targetData); if (response.length > 0) { const objcolumn = Object.keys(response[0]).map(t => ({ col: { title: t, disp: true } })); setColumns(objcolumn); } }); }; useEffect(() => { loadDatabase(); }, [actualcategory]); // 依赖分类参数,分类变化时重新加载 return [categoryData, columns]; }; // Settings组件中直接使用 const Settings = () => { const [data1, columns] = useTable(1, "new"); return <>></>; };
内容的提问来源于stack exchange,提问作者artur nowakowski
相关产品推荐
相关产品推荐

