React 및 GraphQL - 15를 사용하여 Reddit 클론 만들기

이 블로그 게시물은 원래 내 블로그 사이트에 게시되었으며 여기에서 찾을 수 있습니다.



이 블로그 게시물에서 우리는 페이지 매김을 설정할 것입니다. 따라서 많은 데이터를 데이터베이스에 시드해야 합니다. mockaroo 사이트를 사용하여 모의 데이터를 생성하고 해당 데이터를 SQL 쿼리로 내보낼 수 있습니다.

그런 다음 create migration 명령을 실행하여 서버 애플리케이션에서 마이그레이션 파일을 생성합니다.


npx typeorm migration:create -n FakePost



해당 마이그레이션 파일에는 updown 라는 2개의 메서드가 있습니다. 이 코드 줄을 up 메서드에 추가합니다.

await queryRunner.query(`
... mockaroo queries goes here `);


그런 다음 이 마이그레이션 파일을 실행하도록 서버 인덱스 파일을 변경합니다. 해당 파일을 migration 폴더로 이동할 수 있습니다. createConnection 메서드에 마이그레이션 속성을 추가합니다.


migrations: [path.join(__dirname, "./migrations/*")],



그런 다음 해당 메서드 아래에 이 코드 줄을 추가하여 마이그레이션을 실행합니다.

await conn.runMigrations();


이 시점에서 우리는 게시물의 텍스트를 반환하지 않습니다. 그러나 우리는 홈 페이지에 전체 텍스트를 표시하고 싶지 않습니다. 홈 페이지에는 제한된 수의 문자만 표시할 수 있습니다.
@Resolver(Post)에 Resolver 주석을 추가할 수 있으며 FiledResolver를 추가하고 있습니다.


@FieldResolver(() => String)
textSnippet(@Root() root: Post) {
  return root.text.slice(0, 50);
}



또한 마지막 게시물 타임스탬프를 가져와서 이전 게시물을 반환하는 cursorPagination 메서드를 사용하고 있습니다. posts 메서드를 사용자 쿼리 빌더로 변경하고 결과를 제한 개수로 반환할 수 있습니다. 여기에서 limitcursor 로 2개의 매개변수를 사용합니다.


async posts(
@Arg("limit", () => Int) limit: number,
@Arg("cursor", () => String, { nullable: true }) cursor: string | null
): Promise<Post[]> {
  // previously we took all the posts

  // return await Post.find();
  // using query builder
  const realLimit = Math.min(50, limit);
  const qb = getConnection()
  .getRepository(Post)
  .createQueryBuilder("p")
  .orderBy('"createdAt"', "DESC")
  .take(realLimit);

  if (cursor) {
  // take the old post using cursor
  qb.where('"createdAt" < :cursor', {
  cursor: new Date(parseInt(cursor)),
  });
  }
  return qb.getMany();

}




이제 백엔드 코드가 완성되었습니다. 이제 이 두 매개변수와 일치하도록 프런트 엔드graphql 쿼리를 변경해야 합니다.


query Posts($limit: Int!, $cursor: String) {
  posts(cursor: $cursor, limit: $limit) {
    id
    createdAt
    updatedAt
    title
    textSnippet
  }
}



graphql 쿼리를 변경한 후 yarn gen 명령을 실행합니다. 게시물을 검색하기 위해 생성된 메서드를 업데이트합니다.

이제 일부 chakra-ui 구성 요소를 추가하여 게시물의 전망을 변경할 수 있습니다.

헤더를 추가하고 Create Post 링크를 재정렬할 수 있습니다.

<Flex align="center">
  <Heading>Reddit Clone</Heading>
  <NextLink href="/create-post">
    <Link ml="auto">Create Post</Link>
  </NextLink>
</Flex>


처리해야 하는 몇 가지 시나리오가 있습니다. 하나는 데이터가 없고 여전히 가져오는 경우 아래 메시지를 표시해야 합니다.

if (!fetching && !data) {
  return <div>there is some error in graphql query</div>;
}

fetching를 사용하려면 graphql 쿼리에서 할당해야 합니다.


const [{ data, fetching }] = usePostsQuery({
  // ... rest of the code



게시물 스니펫과 함께 게시물을 표시하도록 아래와 같이 post UI를 업데이트할 수 있습니다.


<Stack spacing={8}>
{data!.posts.map((p) => {
return (
  <Box key={p.id} p={5} shadow="md" borderWidth="1px">
    <Heading fontSize="xl">{p.title}</Heading>
    <Text mt={4}>{p.textSnippet} </Text>
  </Box>
);
})}
</Stack> 



그런 다음 데이터가 있는 경우 더 많은 게시물을 로드하는 버튼을 표시할 수 있습니다. 종료</Layout> 태그 위의 코드를 아래에 추가합니다.


{data ? (
<Flex>
  <Button onClick={() => { }); } m="auto" my={8} isLoading={fetching} >
    load more
  </Button>
</Flex>
) : null}



이제 캐시에서 createUrqlClient  에 페이지 매김 리졸버를 추가합니다. 캐시에 있는 게시물을 새 게시물에 추가하는 기능입니다.


const cursorPagination = (): Resolver => {
  return (_parent, fieldArgs, cache, info) => {
    const { parentKey: entityKey, fieldName } = info;
    const allFields = cache.inspectFields(entityKey);
    console.log("allFields: ", allFields);
    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(entityKey, fieldKey);
    info.partial = !isItInTheCache;
    const results: string[] = [];
    fieldInfos.forEach((fi) => {
      const data = cache.resolve(entityKey, fi.fieldKey) as string[];
      console.log(data)
      results.push(...data);
    });

    return results;

  };
};



교환하려면 이것을 cacheExchange  로 설정해야 합니다.


resolvers: {
  Query: {
    posts: cursorPagination(),
  },
},



이제 onClick 기능을 추가할 수 있습니다. 상태를 사용하여 커서를 설정할 수 있습니다. 먼저 cursor 의 초기 조각상을 만듭니다.


const [variables, setVariables] = useState({
  limit: 10,
  cursor: null as null | string,
});



그런 다음 버튼을 클릭하면 커서가 마지막 게시물의 타임스탬프로 변경됩니다. 이렇게 하면 새 게시물을 로드할 수 있습니다.


<Button
  onClick={() => {

  setVariables({
  limit: variables.limit,
  cursor: data.posts[data.posts.length - 1].createdAt,
  });
  }}
  m="auto"
  my={8}
  isLoading={fetching}
>
// ...rest of the code



이제 뷰에서 새 게시물을 업데이트하는 것을 볼 수 있습니다.


읽어주셔서 감사합니다. 이와 관련하여 질문할 사항이 있으면 여기에 댓글을 남겨주세요. 또한 내 이해에 따라 이것을 썼습니다. 따라서 잘못된 점이 있으면 주저하지 말고 저를 수정하십시오. 정말 감사합니다.
오늘의 친구들을 위한 것입니다. 곧 봐요. 고맙습니다.

참조:

이 기사 시리즈는 . 이것은 놀라운 튜토리얼이며 확인하는 것이 좋습니다.

기본 이미지credit

좋은 웹페이지 즐겨찾기