React+TypeScript自定义Hook求助:获取组件Props展示已打开任务
嘿,作为React+TypeScript新手,你尝试自定义Hook的思路方向是对的,但现有代码确实存在几个关键问题(类型不匹配、逻辑缺失、依赖项遗漏等),我来帮你梳理并给出完整的可运行解决方案:
先梳理你现有代码的核心问题
- 类型定义混乱:原Hook类型
type Hook = (TaskID: string) => string和实际逻辑不匹配,而且Task接口里没有title字段,但你却在openTasks里试图访问list.title,这会直接导致TypeScript报错。 - 未利用传入的Props:你的自定义Hook没有接收组件的
lists和tasksProps,根本无法从这些数据中获取任务信息。 - Hooks规则问题:
useEffect没有添加依赖项,会导致组件每次渲染都重复订阅/取消订阅,引发性能问题。 - 状态管理逻辑缺失:你没有根据
TaskID从tasks数组中找到对应的任务,也没有关联lists获取所属列表信息。
完整修正后的代码方案
首先,先补全/修正你的接口定义(假设Task应该有title字段,这是你原代码中试图访问的属性;如果实际需求中Task没有title,可以替换成ref或其他字段):
export interface List { id: string; title: string; } export interface Task { id: string; ref: string; listId: string; title: string; } // 补全title字段 export interface Props { lists: List[]; tasks: Task[]; }
然后是符合规范的自定义Hook:
import { useState, useEffect } from 'react'; // 明确Hook的类型:接收组件Props和目标任务ID,返回打开的任务及所属列表信息 type UseOpenedTaskHook = (props: Props, taskId: string) => { taskTitle: string; listTitle?: string } | null; const useOpenedTask: UseOpenedTaskHook = ({ lists, tasks }, taskId) => { // 定义状态并指定TypeScript类型,初始值为null const [openedTask, setOpenedTask] = useState<{ taskTitle: string; listTitle?: string } | null>(null); // 处理任务订阅的回调函数:根据任务ID匹配数据 const handleTaskOpen = (targetTaskId: string) => { // 从tasks数组中找到对应ID的任务 const foundTask = tasks.find(task => task.id === targetTaskId); if (!foundTask) { setOpenedTask(null); return; } // 根据任务的listId找到所属列表 const foundList = lists.find(list => list.id === foundTask.listId); // 更新状态,存储任务标题和列表标题 setOpenedTask({ taskTitle: foundTask.title, listTitle: foundList?.title }); }; useEffect(() => { // 订阅指定任务ID的变化(这里假设URL.subscribeToTaskId是你项目中已有的订阅API) URL.subscribeToTaskId(taskId, handleTaskOpen); // 清理函数:组件卸载或依赖变化时取消订阅,避免内存泄漏 return () => { URL.unsubscribeFromTaskId(taskId, handleTaskOpen); }; }, [taskId, lists, tasks]); // 添加依赖项:当这些值变化时,重新执行effect // 返回最终的打开任务信息 return openedTask; }; export default useOpenedTask;
如何在组件中使用这个Hook
import useOpenedTask from './useOpenedTask'; const TaskViewer = (props: Props) => { // 这里的taskId可以从URL参数、父组件Props或其他状态中获取 const currentTaskId = 'task-123'; const openedTask = useOpenedTask(props, currentTaskId); return ( <div className="task-viewer"> {openedTask ? ( <div className="opened-task"> <h2>当前打开任务:{openedTask.taskTitle}</h2> {openedTask.listTitle && <p>所属列表:{openedTask.listTitle}</p>} </div> ) : ( <p>暂无打开的任务</p> )} </div> ); }; export default TaskViewer;
关键注意事项
- 自定义Hook必须以
use开头,严格遵循React Hooks规则(比如只能在组件或其他Hook中调用)。 - TypeScript中一定要明确指定状态、函数参数和返回值的类型,避免隐式
any,这能帮你提前发现很多错误。 useEffect的依赖项一定要准确,否则会导致过时闭包或不必要的重渲染。- 如果你的
Task接口确实不需要title字段,只需要把foundTask.title替换成foundTask.ref或其他你需要展示的属性即可。
内容的提问来源于stack exchange,提问作者polycarp royal
相关产品推荐
相关产品推荐

