reactjs 如何在Remix加载器中正确输入延迟响应?

s2j5cfk0  于 2023-04-29  发布在  React
关注(0)|答案(1)|浏览(116)

我正在用一个简单的应用程序学习Remix,该应用程序可以从Twitch频道获取剪辑并将其显示在表格中。我在尝试从Twitch API获取这些数据时遇到了Typescript的一个奇怪问题,不确定该如何继续。
我将Index组件设置为使用来自加载器的延迟值(如下所述:https://beta.reactrouter.com/en/dev/guides/deferred),它有点工作-加载器正在获取并返回正确的信息,我可以看到加载状态显示,然后在加载完成时消失。万岁!但是Typescript抱怨的是数据的实际返回类型。
下面是给我带来困难的代码:

// _index.tsx
type ClipsResponse = {
    count: number;
    clips: ClipDto[];
}

export async function loader({ request }: LoaderArgs) {
    const url = new URL(request.url);
    const broadcasterName = url.searchParams.get("broadcasterName");
    // fetchClips is complicated but returns type Promise<ClipsResponse>
    return defer({ clipData: fetchClips(broadcasterName) });
}

export default function IndexRoute() {
    const data = useLoaderData<typeof loader>();
    return (
        <Suspense fallback={<LoadingSpinner />}>
            <Await
                resolve={data.clipData}
                errorElement={<ClipTableError broadcasterName="" />}
                children={(clipData) => (
                    <div
                        className={`flex flex-1 justify-center my-4 rounded-md bg-slate-50 border-slate-300 border h-full w-full`}
                    >
                        <ClipTable clips={clipData.clips} />
                    </div>
                )}
            />
        </Suspense>
    );
}
// ClipTable.tsx

type ClipTableProps = {
    clips: ClipDto[];
};

const ClipTable = ({ clips = [] }: ClipTableProps) => {
    // do stuff to display clips in table
}

我得到的错误是当试图将clipData.clips传递给<ClipTable />组件时; typescript 错误说:

Type 'SerializeObject<UndefinedToOptional<ClipDto>>[]' is not assignable to type 'ClipDto[]'.
  Type 'SerializeObject<UndefinedToOptional<ClipDto>>' is not assignable to type 'ClipDto'.

我不一定介意必须潜在地解析加载器对数据所做的任何事情来序列化它,但是文档没有说任何关于这种类型的事情,我不确定它来自哪里或者如何处理它。
任何帮助将不胜感激!

omqzjyyz

omqzjyyz1#

useLoaderData钩子不适用于泛型,返回类型unknown
参见来源:

/**
 * Returns the loader data for the nearest ancestor Route loader
 */
export function useLoaderData(): unknown {
  let state = useDataRouterState(DataRouterStateHook.UseLoaderData);
  let routeId = useCurrentRouteId(DataRouterStateHook.UseLoaderData);

  if (state.errors && state.errors[routeId] != null) {
    console.error(
      `You cannot \`useLoaderData\` in an errorElement (routeId: ${routeId})`
    );
    return undefined;
  }
  return state.loaderData[routeId];
}

您可以将data强制转换为正确的类型。通常类似于:

const data = useLoaderData() as ClipsResponse;

事情变得更重时,推迟响应虽然,这些得到包裹在保护的承诺。将解析/延迟值重新转换回unknown,然后转换为您的ClipsResponse类型。
我相信以下内容可能接近您正在寻找的内容。

type ClipsResponse = {
  count: number;
  clips: ClipDto[];
}

...

export default function IndexRoute() {
  const data = useLoaderData();

  return (
    <Suspense fallback={<LoadingSpinner />}>
      <Await
        resolve={data.clipData}
        errorElement={<ClipTableError broadcasterName="" />}
        children={(data) => {
          const clipData = data as unknown as ClipsResponse; // <-- cast here
          return (
            <div
              className="flex fl...ll w-full"
            >
              <ClipTable clips={clipData.clips} />
            </div>
          );
        }}
      />
    </Suspense>
  );
}

相关问题