graphQL

Provider

보통 index에서 useContext Provider처럼 App 자체를 싼다.

client를 하나 설정하고 그걸 따서 Provider로 제공한다고 생각하면 됨.

client

import { ApolloClient, InMemoryCache, gql } from '@apollo/client';

const client = new ApolloClient({
  uri: 'http://localhost:4000/',
  cache: new InMemoryCache(),
});

index에서 사용

import React from 'react';
import ReactDOM from 'react-dom/client';
import './index.css';
import App from './App';
import client from './client';
import { ApolloProvider } from '@apollo/client';

const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
  <React.StrictMode>
    {/* Provider로 App 전체에 ApolloProvider client를 사용할 수 있게 뿌려줌 */}
    <ApolloProvider client={client}>
      <App />
    </ApolloProvider>
  </React.StrictMode>
);

원래 사용법

const Movies = () => {
  // client로 접근 가능.
  const [movies, setMovies] = useState([]);
  const client = useApolloClient();
  useEffect(() => {
    client
      .query({
        query: gql`
          {
            allMovies {
              title
              id
            }
          }
        `,
      })
      .then((results) => setMovies(results.data.allMovies));
  }, [client]);
  return (
    <div>
      {movies.map((movie) => (
        <li key={movie.id}>{movie.title}</li>
      ))}
    </div>
  );
};

매일 client를 끌고와야 하는 단점, state를 매일 만들어서 넣어야 하는 단점들.

그러므로 useQuery라는 hook을 사용.

구조분해 할당으로 받을 수 있음.

import { gql, useQuery } from '@apollo/client';

const ALL_MOVIES = gql`
  {
    allMovies {
      title
      id
    }

    allTweets {
      id
      text
      author {
        fullName
      }
    }
  }
`;


const Movies = () => {
  const { data, loading, error } = useQuery(ALL_MOVIES);
  if (loading) {
    return <h1>Loading...</h1>;
  }
  if (error) {
    return <h1>Could not fetch :(</h1>;
  }
  return (
    <ul>
      <h1>Movies</h1>
      {data.allMovies.map((movie) => (
        <li key={movie.id}>{movie.title}</li>
      ))}
      <h1>Tweets</h1>
      {data.allTweets.map((tweet) => (
        <li key={tweet.id}>
          {tweet.text}/by: {tweet.author.fullName}
        </li>
      ))}
    </ul>
  );
};

변수를 필요로하는 쿼리로 변수를 보내는


server code

const typeDefs = gql`
  type User {
    id: ID!
    firstName: String!
    lastName: String!
    fullName: String!
  }

  type Tweet {
    id: ID!
    text: String!
    author: User
  }

  type Query {
    allMovies: [Movie!]!
    allUsers: [User!]!
    allTweets: [Tweet!]!
    tweet(id: ID!): Tweet
    movie(id: String!): Movie
  }

  type Mutation {
    postTweet(text: String!, userId: ID!): Tweet!
    deleteTweet(id: ID!): Boolean!
  }
  type Movie {
    id: String!
    url: String!
    imdb_code: String!
    title: String!
    title_english: String!
    title_long: String!
    slug: String!
    year: Int!
    rating: Float!
    runtime: Float!
    genres: [String]!
    summary: String
    description_full: String!
    synopsis: String
    yt_trailer_code: String!
    language: String!
    background_image: String!
    background_image_original: String!
    small_cover_image: String!
    medium_cover_image: String!
    large_cover_image: String!
  }
`;

const resolvers = {
  Query: {
    allTweets() {
      return tweets;
    },
    tweet(root, { id }) {
      return tweets.find((tweet) => tweet.id === id);
    },
    allUsers() {
      return users;
    },
    async allMovies() {
      const r = await fetch('https://yts.mx/api/v2/list_movies.json');
      const json = await r.json();
      return json.data.movies;
    },
    async movie(_, { id }) {
      const r = await fetch(
        `https://yts.mx/api/v2/movie_details.json?movie_id=${id}`
      );
      const json = await r.json();
      return json.data.movie;
    },
  }

Client code

const GET_MOVIE = gql`
  query getMovie($movieId: String!) {
    movie(id: $movieId) {
      id
      title
    }
  }
`;

const Movie = () => {
  const params = useParams();
  const { data, loading } = useQuery(GET_MOVIE, {
    variables: {
      movieId: params.id,
    },
  });
  console.log(data, loading);
  console.log(typeof params.id);

  if (loading) {
    return <h1>Fetching movie...</h1>;
  }
  return <div>{data.movie.title}</div>;
};

export default Movie;

Apollo cache

위에 클라이언트 코드를 다시 보자.

import { ApolloClient, InMemoryCache, gql } from '@apollo/client';

const client = new ApolloClient({
  uri: 'http://localhost:4000/',
  cache: new InMemoryCache(),
});

export default client;

여기에서 new InMemoryCache()는 Apollo cache를 의미한다.

이게 필요한 이유는 유저가 브라우저에서 한번 들어갔던 것을 케시에 저장해놓아서 다시 들어가도 로딩을 새로 하지 않아 속도가 빠르게 적용이 된다.

즉, apollo cache -> 들어갔던 쿼리를 메모리에 저장해서 다시 로딩을 하지 않는다.

효율적이라는 뜻!!

notifyOnNetworkStatusChange

Apollo Client는 GraphQL을 사용하여 서버와의 통신을 관리하는 클라이언트 라이브러리이다. notifyOnNetworkStatusChange 옵션은 Apollo Client의 네트워크 상태 변경을 감지하고 해당 상태 변경에 대한 알림을 받을지 여부를 결정하는 옵션이다.

기본적으로 notifyOnNetworkStatusChange는 false로 설정되어 있다.
이는 네트워크 상태 변경에 대한 알림을 받지 않는 것을 의미한다.
그러나 notifyOnNetworkStatusChange를 true로 설정하면, Apollo Client는 네트워크 상태가 변경될 때마다 networkStatus 필드가 포함된 추가적인 정보를 반환한다.

networkStatus 필드는 Apollo Client가 관리하는 네트워크 상태에 대한 정보를 담고 있다.
이 정보를 활용하여 UI에 로딩 상태 표시, 에러 처리, 캐시 갱신 등을 구현할 수 있다.

따라서 notifyOnNetworkStatusChange: true를 설정하면 Apollo Client에서 네트워크 상태 변경을 감지하고 networkStatus 필드를 통해 해당 상태를 제공한다.

보통 내용이 변하지 않으면 useQeury를 사용할 때 query를 불러오지 않는 경우가 있는데, 그럴 경우 사용한다.

 const getDrawingResult = useQuery(GET_DRAWING_CEPPROS, {
    notifyOnNetworkStatusChange: true,
    variables: {
      filters: {
        id: {
          eq: viewerState.cepproId
        }
      }
    }
  });

variables 분기

query문에서 variables에 조건을 넣는데, 분기를 치고 싶은 경우 이렇게 사용

const getPatientList = useQuery(GET_All_PATIENT_OF_DOCTOR, {
        variables: {
            filters: {
                ddhaim_user: {
                    id: {
                        eq: 17,
                    },
                },
                ...(isSearch ? { first_name: { contains: searchInput } } : {}), //이 부분!!
            },
            pagination: {
                pageSize: 10,
                page: currentPage,
            },
        },

Client Mutation

여기 참조

https://www.apollographql.com/docs/react/data/mutations/

이해하기가 조금 어렵기는 한 것 같다.

좀 써보면서 숙달해야 알 수 있을 것 같은 느낌..

profile
코딩 일기장

0개의 댓글