You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

React+TypeScript自定义Hook求助:获取组件Props展示已打开任务

嘿,作为React+TypeScript新手,你尝试自定义Hook的思路方向是对的,但现有代码确实存在几个关键问题(类型不匹配、逻辑缺失、依赖项遗漏等),我来帮你梳理并给出完整的可运行解决方案:

先梳理你现有代码的核心问题

  1. 类型定义混乱:原Hook类型type Hook = (TaskID: string) => string和实际逻辑不匹配,而且Task接口里没有title字段,但你却在openTasks里试图访问list.title,这会直接导致TypeScript报错。
  2. 未利用传入的Props:你的自定义Hook没有接收组件的lists和tasks Props,根本无法从这些数据中获取任务信息。
  3. Hooks规则问题:useEffect没有添加依赖项,会导致组件每次渲染都重复订阅/取消订阅,引发性能问题。
  4. 状态管理逻辑缺失:你没有根据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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.07 07:04:06