Github graphQL 및 REST api를 사용한 반응 쿼리 팁 및 요령

React의 독단적인 특성에 대한 좋은 점 중 하나는 커뮤니티가 몇 가지 훌륭한 솔루션을 제시할 수 있다는 것입니다. 그 중 하나는 다른 프레임워크로 확장되었기 때문에 이제 tanstack-query로 가는 react-query입니다.

react-query 를 사용해야 한다면 아마도 . ap가 많은 네트워크 요청에 의존하는 경우 redux와 같은 것을 사용하기 전에 고려해야 합니다.

반응 쿼리는 데이터를 가져오는 방법에 대해 의견이 분분하다는 점을 명심하세요. 그 작업은 응답 및 오류/로딩 상태와 캐시 및 재시도를 처리하는 것입니다.

아래에 링크된 전체 코드, 프로젝트에서의 사용 예


티가와나 / 자식들






내가 gitpals라고 부르는 어리석은 작은 앱


github 서클을 확장하고 그 과정에서 새로운 개발자를 찾으십시오.


github rest api를 사용하고 vite /br>로 반응합니다.


스크립트
npm run dev

to start the dev server

npm run deploy

To deploy your site to gitpages

*this requires a bunch of initial set-up

Add add your github personal access token in the field , to clear it from local storage click on the profile pic icon on the right end of the toolbar

live preview on live page link

협업에 개방적

fork the repo and make a pull request if you make any progress

유용한 링크





티가와나 / 깃덱

깃덱

You'll need a personal access token to login
live preview

You multiple points of entry into the rabbit hole , either cllick on follower/ following tabs and click on a profile which wil then expose you to their repos and followers/following or just look up a username or email anf follow that one , have fun , make friends and learn something new

내장

Nextjs 특성

This is a Next.js project bootstrapped with create-next-app.

시작하기

First, run the development server:

npm run dev
# or
yarn dev

Open http://localhost:3000 with your browser to see the result.

You can start editing the page by modifying pages/index.tsx. The page auto-updates as you edit the file.

initialization is simple
step 1 : create the actual async query function which returns a response or error

rest api
i'll use axios , you can use fetch too

const fetchdatas=async()=>{
const token ="token token token "
const url="https://api.github.com/user"
   const res = await axios({
        method: 'get',
        url: url,
        headers: {
            Authorization: `Bearer ${token}`,
            "Content-Type": "application/json"
        },
    })
    // //console.log("response == ",res)

    const user = res.data 
    // //console.log("authed user == ",user)
    return user
}

graphql API
저는 graphql-request를 사용하겠습니다.

 const USER = gql`
         query getMiniUser($name: String!) {
           user(login: $name) {
             login
             id
             isFollowingViewer
             viewerIsFollowing
             bio
             avatarUrl
             isViewer
             url
           }
         }
       `;
const graphQLClient = new GraphQLClient(endpoint, headers);
const fetchData = async () => await graphQLClient.request(USER,{name:"tigawanna);

2단계: useQuery의 경우 쿼리 후크에 연결합니다.

const key =['user']
useQuery(key, fetchData,);

다음은 대부분의 프로젝트에서 계속 도달할 수 있는 몇 가지 팁과 요령입니다.
  • 1 열쇠
    react-quryke는 배열이며, 첫 번째 항목은 고유한 문자열이며 이름 변수가 변경되면 쿼리를 다시 실행하려는 경우와 같이 쿼리가 의존하는 모든 변수를 추가할 수도 있습니다.

  • const key =['user',name_variable]
    useQuery(key, fetchData);
    

  • 2 사용 옵션: 불필요한 쿼리를 피하기 위해 특정 조건이 충족된 후에만 쿼리가 실행되도록 하는 것이 매우 일반적입니다.

  • const key =['user']
    useQuery(key, fetchData,
    {
    enabled:name_variable !== "" && name_variable.length > 3
    );
    

  • 3 선택 옵션: 반환된 데이터에 액세스할 수 있는 기능이며 렌더링하기 전에 클라이언트 측에서 데이터를 수정할 수 있습니다.

  • const query = useQuery(key, fetchData,
    {
    enabled: username.length > 3,
      select: (data:User) => {
     let newdata   
      if (data.user.isViewer){
      newdata = {...data.user,OP:true}
      return {user:newdata}
      }
      return data
      }
    }
    )
    

    선택 옵션을 사용하여 항목을 재정렬하고 데이터를 가져오지 않고 항목 배열을 필터링할 수도 있습니다.

    const keyword = "a"
    const query = useQuery(key, fetchData,
    {
    enabled: username.length > 3,
      select: (data:User) => {
     let newdata   
      if (keyword){
      const followers = data.user.followers.edges.filter((item)=>{
       return item.node.login.includes(keyword)
      })  
      newdata = {...data.user,followers}
      return {user:newdata}
      }
      return data
      }
    }
    )
    

  • 4 onError 및 onSuccess 부작용: 이 함수는 이러한 이벤트가 발생할 때 호출됩니다. 오류 코드가 401 또는 402인 경우 github 개인 액세스 토큰을 자동으로 무효화하고 onSuccess 내부에서 문제가 발생하지 않으면 로컬 저장소에 저장하는 데 사용했습니다.

  • const query = useQuery(key, fetchData,
    {
    enabled: username.length > 3,
      select: (data:User) => {
     let newdata   
      if (keyword){
      const followers = data.user.followers.edges.filter((item)=>{
       return item.node.login.includes(keyword)
      })  
      newdata = {...data.user,followers}
      return {user:newdata}
      }
      return data
      },
      onSuccess:(data:User)=>{
        console.log("success")
    //save token to local storage no issues with it
      },
      onError:(error:any)=>{
        console.log("error  = ",error.response)
        if(error?.response?.status === "401" || error?.response?.status === "402"){
          // invalidate my locally stored token to send me back to 
          // login screen,those codes mean tokenhas an issue
        }
      }
    }
    )
    

    보너스 팁: useInfiniteQuery 후크

    useInfiniteQuery 후크는 긴 데이터 목록의 페이지 매김을 처리하기 위한 것입니다.
    예를 들어 graphql 쿼리에서 매우 긴 목록을 가질 수 있는 팔로워와 같은 필드에 매개 변수를 먼저 전달할 수 있습니다.

    그래서 우리는 이렇게 페이지 매김을 소개합니다

    const query = useInfiniteQuery(key, fetchData, {
      enabled: username.length > 3,
     onSuccess: (data: RootResponse) => {
        console.log("success", data);
      },
      onError: (error: any) => {
        console.log("error  = ", error.response);
        if (error?.response?.status === "401" || error?.response?.status === "402") {
          // invalidate my locally stored token to send me back to
          // login screen,those codes mean tokenhas an issue
        }
      },
      getPreviousPageParam: (firstPage: Page) => {
        return firstPage?.user?.followers?.pageInfo?.startCursor ?? null;
      },
      getNextPageParam: (lastPage: Page) => {
        return lastPage?.user?.followers?.pageInfo?.endCursor ?? null;
      },
    });
    console.log("test query === ",query.data)
    

    추가 로드 버튼 추가

      const pages = query?.data?.pages;
      //  console.log("followers === ",followers)
      //@ts-ignore
      const extras = pages[pages.length - 1].user?.followers;
      const hasMore = extras?.pageInfo?.hasNextPage;
    
    return (
      <div className="w-full h-full ">
        {!query.isFetchingNextPage && hasMore? (
          <button
            className="m-2 hover:text-purple-400 shadow-lg hover:shadow-purple"
            onClick={() => {
              query.fetchNextPage();
            }}
          >
            --- load more ---
          </button>
        ) : null}
        {query.isFetchingNextPage ? (
          <div className="w-full flex-center m-1 p-1">loading more...</div>
        ) : null}
      </div>
    )
    
    

    기본적으로 반응 쿼리는 페이지 배열에 새 배열을 추가하고 중첩 루프를 사용하여 데이터를 출력해야 하는 페이지 배열로 데이터를 반환합니다.

        <div className="h-fit w-full flex-center  flex-wrap">
          {pages?.map((page) => {
            return page?.user?.followers?.edges?.map((item) => {
              return (
                <div className='w-[30%] h-14 p-3 m-2 border border-green-500 '>
                  user :{item.node.login}</div>
              );
            });
          })}
        </div>
    
    

    또한 페이지 매김 getNextPageParam 및 getPreviousPageParam을 처리하기 위해 반응 쿼리에서 제공하는 부작용 함수에 유의하십시오.
    이 경우 API가 pageInfo 필드 내부에 제공하는 종료 커서를 전달된 쿼리 함수에 값을 삽입합니다.

    이 경우 변경하겠습니다.

    const fetchData = async () => await graphQLClient.request(USER,{name:"tigawanna",
    first:10,after:null
    });
    
    

    ~ 안으로

    const fetchData = async (deps: any) => {
        const after = deps?.pageParam ? deps.pageParam : null;
        return await graphQLClient.request(USER, {
          name: "tigawanna",
          first: 10,
          after,
        });
      };
    
    

    그리고 우리는 그것의 가치를 받을 deps에서 그것을 가져올 것입니다.

      getNextPageParam: (lastPage: Page) => {
        return lastPage?.user?.followers?.pageInfo?.endCursor ?? null;
      },
    
    

    이것은 잘 작동하지만 특정 키워드를 필터링하려는 경우 상황이 까다로워 데이터를 단일 배열로 변환하고 제공된 모든 키워드를 필터링하는 함수를 만들었습니다.

    export const concatFollowerPages = (data: RootResponse, keyword: string) => {
    
    let totalRepos = data.pages[0].user.followers.edges;
      let i = 1;
      for (i = 1; i < data.pages.length; i++) {
        if (data?.pages) {
          totalRepos = [...totalRepos, ...data.pages[i].user.followers.edges];
        }
      }
    
      const filtered = totalRepos.filter((item) =>
        item.node.login.toLowerCase().includes(keyword.toLowerCase())
      );
      const base = data.pages[data.pages.length -1].user;
      const user = {
        ...base,
        login: base.login,
        followers: {
          edges: filtered,
          totalCount: base.followers.totalCount,
          pageInfo: base.followers.pageInfo,
        },
      };
    
      const final:RootResponse = {
        pageParams: [...data.pageParams],
        pages: [{ user: user }],
      };
    
      return final;
    };
    
    

    그런 다음 select 내부에서 호출합니다.

    const query = useInfiniteQuery(key, fetchData, {
      enabled: username.length > 3,
      select:(data:RootResponse)=>{
      return concatFollowerPages(data,"")
      },
      onSuccess: (data: RootResponse) => {
        // console.log("success", data);
      },
      onError: (error: any) => {
        console.log("error  = ", error.response);
        if (error?.response?.status === "401" || error?.response?.status === "402") {
          // invalidate my locally stored token to send me back to
          // login screen,those codes mean tokenhas an issue
        }
      },
      getPreviousPageParam: (firstPage: Page) => {
        return firstPage?.user?.followers?.pageInfo?.startCursor ?? null;
      },
      getNextPageParam: (lastPage: Page) => {
        return lastPage?.user?.followers?.pageInfo?.endCursor ?? null;
      },
    });
    

    전체 예제 코드의 경우 이해하기 쉽도록 모든 것을 자체 포함된 구성 요소에 압축했습니다.


    좋은 웹페이지 즐겨찾기