我正在实现光标分页以创建无限滚动的帖子,基于文档中 URQL 的简单分页示例。它工作得很好,我得到了我想要的所有信息的帖子......直到缓存通过在我的函数中设置info.partial
为无效。然后我得到.true
cursorPagination()
project: null
我想知道我是否需要做一些特别的事情来缓存来自字段解析器(数据加载器)的结果?我还有其他关系,除了post.project
它们的行为符合预期,所以它必须是这个字段解析器特有的东西......它是唯一可以为空的,也许它与这个事实有关,但为什么它最初会返回值和然后在info.partial
设置为时丢失它true
?
这是我的代码,如果我应该分享更多内容以阐明问题,请告诉我。提前致谢。
createProjectLoader.ts
import DataLoader from "dataloader";
import { Project } from "../entities/Project";
export const createProjectLoader = () => new DataLoader<number, Project>(async projectIds => {
const projects = await Project.findByIds(projectIds as number[]);
const projectIdToProject: Record<number, Project> = {};
projects.forEach(p => {
projectIdToProject[p.id] = p;
});
return projectIds.map((projectId) => projectIdToProject[projectId])
})
解析器/post.ts
@FieldResolver(() => Project, { nullable: true })
project(
@Root() post: Post,
@Ctx() { projectLoader }: MyContext
) {
return post.projectId ? projectLoader.load(post.projectId) : undefined
}
...
@Query(() => PaginatedPosts)
async posts(
@Arg('limit', () => Int) limit: number,
@Arg('cursor', () => String, { nullable: true }) cursor: string | null,
): Promise<PaginatedPosts> {
const realLimit = Math.min(20, limit);
const realLimitPlusOne = realLimit + 1;
const replacements: any[] = [realLimitPlusOne];
if (cursor) {
replacements.push(new Date(parseInt(cursor)));
}
const posts = await getConnection().query(`
select p.*
from post p
${cursor ? `where p."createdAt" < $2` : ""}
order by p."createdAt" DESC
limit $1
`,
replacements
)
return {
posts: posts.slice(0, realLimit),
hasMore: posts.length === realLimitPlusOne
};
}
创建UrqlClient.ts
const cursorPagination = (): Resolver => {
return (_parent, fieldArgs, cache, info) => {
const { parentKey: entityKey, fieldName } = info;
const allFields = cache.inspectFields(entityKey);
const fieldInfos = allFields.filter((info) => info.fieldName === fieldName);
const size = fieldInfos.length;
if (size === 0) {
return undefined
}
const fieldKey = `${fieldName}(${stringifyVariables(fieldArgs)})`
const isItInTheCache = cache.resolve(
cache.resolveFieldByKey(entityKey, fieldKey) as string,
'posts'
);
info.partial = !isItInTheCache;
let hasMore = true;
const results: string[] = [];
fieldInfos.forEach(fi => {
const key = cache.resolveFieldByKey(entityKey, fi.fieldKey) as string;
const data = cache.resolve(key, 'posts') as string[];
const _hasMore = cache.resolve(key, 'hasMore');
if (!_hasMore) {
hasMore = _hasMore as boolean;
}
results.push(...data);
})
return {
__typename: 'PaginatedPosts',
hasMore,
posts: results
}
}
}