Skip to main content

React Query Kit

文本内容来自React Query Kit: README-CN.md

react-query-kit

🕊️ 一个用于 ReactQuery 的工具包,它能使 ReactQuery 更易复用和类型安全

Latest buildLatest published versionBundlephobiaDependency count 0Types includedLicenseNumber of downloadsGitHub Stars

Motivation

  • 使 queryKeyqueryFn 强相关
  • 以类型安全的方式管理 queryKey
  • 快速生成自定义 ReactQuery 钩子
  • queryClient 的操作更清楚地关联到哪个自定义 ReactQuery 钩子
  • 为自定义 ReactQuery 钩子设置默认选项更容易和更清晰

react-query-kit.gif

Table of Contents

Installation

$ npm i react-query-kit
# or
$ yarn add react-query-kit

Examples

createQuery

Usage

import { QueryClient, dehydrate } from '@tanstack/react-query'
import { createQuery } from 'react-query-kit'

type Response = { title: string; content: string }
type Variables = { id: number }

const usePost = createQuery<Response, Variables, Error>({
primaryKey: '/posts',
queryFn: ({ queryKey: [primaryKey, variables] }) => {
// primaryKey 相等于 '/posts'
return fetch(`${primaryKey}/${variables.id}`).then(res => res.json())
},
// 如果你只想在没有数据时请求,可以这么设置
enabled: (data) => !data,
suspense: true
})

// 你也可以使用以下的语法来创建自定义hook
// const usePost = createQuery<Response, Variables, Error>(
// '/posts',
// ({ queryKey: [primaryKey, variables] }) => {
// // primaryKey 相等于 '/posts'
// return fetch(`${primaryKey}/${variables.id}`).then(res => res.json())
// },
// {
// // if u only wanna fetch once
// enabled: (data) => !data,
// suspense: true
// }
// )


const variables = { id: 1 }

// example
export default function Page() {
// queryKey 相等于 ['/posts', { id: 1 }]
const { data } = usePost({ variables, suspense: true })

return (
<div>
<div>{data?.title}</div>
<div>{data?.content}</div>
</div>
)
}

console.log(usePost.getKey()) // ['/posts']
console.log(usePost.getKey(variables)) // ['/posts', { id: 1 }]

// nextjs 例子
export async function getStaticProps() {
const queryClient = new QueryClient()

await queryClient.prefetchQuery(usePost.getKey(variables), usePost.queryFn)

return {
props: {
dehydratedState: dehydrate(queryClient),
},
}
}

// 在 react 组件外使用
const data = await queryClient.fetchQuery(
usePost.getKey(variables),
usePost.queryFn
)

// useQueries 例子
const queries = useQueries({
queries: [
{ queryKey: usePost.getKey(variables), queryFn: usePost.queryFn },
{ queryKey: useProjects.getKey(), queryFn: useProjects.queryFn },
],
})

// setQueryData
queryClient.setQueryData(usePost.getKey(variables), {...})

额外的 API 文档

Options

  • primaryKey: string
    • 必填
    • primaryKey 将是 queryKey 数组的第一个元素
  • enabled: boolean | ((data: TData) => boolean)
    • Optional
    • 将此设置为 false 以禁用此查询自动运行。
    • 如果设置为函数,该函数将使用最新数据执行以计算布尔值

Expose Methods

  • getPrimaryKey: () => primaryKey
  • getKey: (variables: TVariables) => [primaryKey, variables]
  • queryFn: QueryFunction<TFnData, [primaryKey, TVariables]>

Returns

  • setData: (updater: Updater<TData>, options?: SetDataOptions) => TData | undefined
    • 它的参数与 queryClient.setQueryData 类似,但不需要传入 queryKey

createInfiniteQuery

Usage

import { QueryClient, dehydrate } from "@tanstack/react-query";
import { createInfiniteQuery } from "react-query-kit";

type Data = { projects: { id: string; name: string }[]; nextCursor: number };
type Variables = { active: boolean };

const useProjects = createInfiniteQuery<Data, Variables, Error>({
primaryKey: "projects",
queryFn: ({ queryKey: [_primaryKey, variables], pageParam = 1 }) => {
return fetch(
`/projects?cursor=${pageParam}?active=${variables.active}`
).then((res) => res.json());
},
getNextPageParam: (lastPage, pages) => lastPage.nextCursor,
});

const variables = { active: true };

// example
export default function Page() {
// queryKey equals to ['projects', { active: true }]
const { data, fetchNextPage, hasNextPage, isFetching, isFetchingNextPage } =
useProjects({ variables, suspense: true });

return (
<div>
{data.pages.map((group, i) => (
<React.Fragment key={i}>
{group.projects.map((project) => (
<p key={project.id}>{project.name}</p>
))}
</React.Fragment>
))}
<div>
<button
onClick={() => fetchNextPage()}
disabled={!hasNextPage || isFetchingNextPage}
>
{isFetchingNextPage
? "Loading more..."
: hasNextPage
? "Load More"
: "Nothing more to load"}
</button>
</div>
<div>{isFetching && !isFetchingNextPage ? "Fetching..." : null}</div>
</div>
);
}

// nextjs example
export async function getStaticProps() {
const queryClient = new QueryClient();

await queryClient.prefetchInfiniteQuery(
useProjects.getKey(variables),
useProjects.queryFn
);

return {
props: {
dehydratedState: dehydrate(queryClient),
},
};
}

// 在 react 组件外使用
const data = await queryClient.fetchInfiniteQuery(
useProjects.getKey(variables),
useProjects.queryFn
);

额外的 API 文档

Options

  • primaryKey: string
    • 必填
    • primaryKey 将是 queryKey 数组的第一个元素
  • enabled: boolean | ((data: TData) => boolean)
    • Optional
    • 将此设置为 false 以禁用此查询自动运行。
    • 如果设置为函数,该函数将使用最新数据执行以计算布尔值

Expose Methods

  • getPrimaryKey: () => primaryKey
  • getKey: (variables: TVariables) => [primaryKey, variables]
  • queryFn: QueryFunction<TFnData, [primaryKey, TVariables]>

Returns

  • setData: (updater: Updater<TData>, options?: SetDataOptions) => TData | undefined
    • 它的参数与 queryClient.setQueryData 类似,但不需要传入 queryKey

createMutation

Usage

import { createMutation } from "react-query-kit";

const useAddTodo = createMutation(
async (data: { title: string; content: string }) =>
fetch("/post", {
method: "POST",
headers: {
Accept: "application/json",
"Content-Type": "application/json",
},
body: JSON.stringify(data),
}).then((res) => res.json()),
{
onSuccess(data, variables, context) {
// do somethings
},
}
);

function App() {
const mutation = useAddTodo({
onSettled: (data, error, variables, context) => {
// Error or success... doesn't matter!
},
});

return (
<div>
{mutation.isLoading ? (
"Adding todo..."
) : (
<>
{mutation.isError ? (
<div>An error occurred: {mutation.error.message}</div>
) : null}

{mutation.isSuccess ? <div>Todo added!</div> : null}

<button
onClick={() => {
mutation.mutate({ title: "Do Laundry", content: "content..." });
}}
>
Create Todo
</button>
</>
)}
</div>
);
}

// usage outside of react component
useAddTodo.mutationFn({ title: "Do Laundry", content: "content..." });

额外的 API 文档

Returns

  • getKey: () => MutationKey
  • mutationFn: MutationFunction<TData, TVariables>

Issues

Looking to contribute? Look for the [Good First Issue][good-first-issue] label.

🐛 Bugs

请针对错误、缺少文档或意外行为提出问题。

[See Bugs][bugs]

💡 Feature Requests

请提交问题以建议新功能。 通过添加对功能请求进行投票 一个 👍。 这有助于维护人员优先处理要处理的内容。

[See Feature Requests][requests]

LICENSE

MIT