[graphql] ApolloClient에서 cache된 readQuery값이 null으로 표시되는 경우 ☹️

dev stefanCho·2022년 5월 12일
0

graphql

목록 보기
1/1

readQuery, writeQuery의 역할

readQuery는 cache에 있는 query를 가져옵니다.
writeQuery는 query를 cache하게 됩니다.

시나리오

시나리오는 다음과 같습니다.

job list를 홈페이지에서 가져오고, 유저가 새로운 job을 포스팅하려고 합니다. 포스팅과정에서 현재 cache되어 있는 job list를 가져오고 싶습니다.

  1. job list를 query하여, cache에 저장되었습니다. (query.js 주석참고)
  2. job을 POST하면서, cache되어있던 job list를 가져오려고 합니다. (mutation.js 주석참고)

하지만 mutation.js의 readQuery결과값은 null으로 나타났습니다. 분명 job list를 먼저 가져왔기 때문에 cache되어있는 값이 읽혀야 합니다.

// query.js
const client = new ApolloClient({
  uri: GRAPHQL_REQUEST,
  cache: new InMemoryCache(),
  headers: {
    authorization: token ? `Bearer ${token}` : "",
  },
})

const QUERY_JOBS = gql`
  {
    jobs {
      id
      title
        company {
          id
          name
          description
        }
    } 
  }
`

// #1. job list를 query하여, cache에 저장되었습니다.
export async function getJobs(id) {
  const { data: { jobs } } = await client.query({ query: QUERY_JOBS });
  return jobs;
}
// mutation.js
const client = new ApolloClient({
  uri: GRAPHQL_REQUEST,
  cache: new InMemoryCache(),
  headers: {
    authorization: token ? `Bearer ${token}` : "",
  },
})

const QUERY_JOBS = gql`
  {
    jobs {
      id
      title
        company {
          id
          name
          description
        }
    } 
  }
`

export async function createJob({ title, description, companyId }) {
  const mutation = gql`
    mutation CreateJob($input: CreateJobInput!) {
      job: createJob(input: $input) {
        id
        title
        description
          company {
            id
            name
            description
          }
      }
    }
  `
  const variables = { input: { title, description, companyId } }
  const { data: { job } } = await client.mutate({
    mutation,
    variables,
    update: async (cache, { data: { job } }) => {
      // #2. job을 POST하면서, cache되어있던 job list를 가져오려고 합니다.
      const read = await client.readQuery({
  	  	query: QUERY_JOBS,
  	  })
      // 하지만 결과는 null 입니다.
  	  console.log('read::', read);
    }
  });
 
  return job;
}

원인

ApolloClient의 인스턴스를 각 파일마다 생성한 것이 문제가 되었습니다. InMemoryCache는 각각의 인스턴스에 적용됩니다.(즉 인스턴스마다 cache가 있습니다.) 따라서 ApolloClient의 인스턴스는 root파일에 한번만 생성하고, import하여 사용하여야 합니다.
실제로 ApolloClient의 Docs를 보면 ApolloProvider에 client props에 생성한 인스턴스를 넣어주고 있습니다. (Docs 참고)

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

ReactDOM.render(
  <ApolloProvider client={client}>
    <MyRootComponent />
  </ApolloProvider>,
  document.getElementById('root'),
);

결론

너무 당연하지만, 이런실수를 하지 않도록 인스턴스 생성시 유의해야하겠습니다.
이 원인을 찾는데에 3시간을 삽질하였습니다.
끝.

profile
Front-end Developer

0개의 댓글