데이터를 주고 받기 위해서 브라우저에서 데이터를 요청하면 요청 받은 백엔드 컴퓨터는 데이터베이스에서 데이터를 처리하여 브라우저에 응답을 돌려줍니다.
이때, 게시글을 등록 후 게시글을 불러왔을 때 게시글이 불러와지지 않는 경우가 있습니다. 이러한 문제는 게시글 등록 요청 후 백엔드 컴퓨터에 요청을 전송하고 데이터가 처리된 후 게시글 불러오기 과정이 실행되어야 하는데 데이터 처리 이전에 게시글 불러오기 과정이 실행되어져 문제가 발생합니다.
이러한 실행 방식을 비동기 실행이라고 합니다.
비동기 실행 방식과 이러한 비동기 실행 방식을 보완하기 위한 다른 통신 방식(동기 실행)이 있습니다.
하지만 우리가 이전에 게시글 등록 후 불러왔을 때 게시글이 불러와지지 않는 오류에 직면한 것처럼 비동기 실행 방식이 아닌 다른 통신 방식을 사용해야할 경우가 있씁니다. 이러한 경우에 사용하는 것이 동기 실행 방식입니다.
동기 실행 방식은 등록 요청을 하게 되면 등록 과정이 모두 완료될 때까지 기다려준 후 게시글 불러오기 과정이 실행되기 때문에 문제 없이 작업이 가능합니다.
동기/비동기 처리 방식비동기 통신
function 함수이름() {
const data = axios.data('https://koreajson.com/posts/1')
console.log(data) // Promise
}
Rest-API에서 데이터의 요청과 응답을 위해 Axios를 사용하여 비동기 통신을 사용해주었습니다. 이 때에 코드는 상단에서부터 실행되면서 백엔드 컴퓨터에 데이터를 요청하고 데이터를 가져와서 응답을 줍니다.
위 코드는 요청된 응답을 가져와 데이터에 저장하고, 저장된 데이터를 콘솔 창에 찍어주도록 작성된 코드입니다.
해당 코드를 실행하면 콘솔창에는 return된 Promise 객체가 보여지게 됩니다.
우리가 해당 코드에서 Promise 객체가 아닌 요청된 데이터 값을 받아오는 방법은 async/await을 사용하게 됩니다.
Promise 객체 는 JavaScript에서 비동기 처리에서 사용되는 객체입니다. 주로 서버에서 받아온 데이터를 화면에 표시하기 위해서 사용하며 데이터를 받아오기도 전에 데이터를 화면에 표시하려고 하면 오류가 발생하거나 빈 화면이 뜨게 되는데, 이러한 문제를 해결하기 위한 방법 중 하나입니다.
Promise에는 3가지 상태가 존재합니다. 여기서 상태란 처리 과정을 의미합니다.
- Pending(대기) : 비동기 처리 로직이 아직 완료되지 않은 상태
- Fulfilled(이행) : 비동기 처리가 완료되어 Promise가 결과 값을 반환해 준 상태
- Rejected(실패) : 비동기 처리가 실패하거나 오류가 발생한 상태
동기 통신(async/await)
async function 함수이름() {
const data = await axios.get('https://koreanjson.com/posts1')
console.log(data) // {id: 1, title: "정당의 목적이나 활동이 ...", ...}
}
우리가 비동기 실행 방식에서 실행 방식으로 변경해주기 위해서는 async/await이 필요합니다.
위 코드처럼 await를 사용하기 위해서는 꼭 async를 작성해야합니다.
apollo-client 설치 후, 사용하기 위해서는 처음 세팅이 필요합니다.
아래와 같이 _app.js에 작성해줍니다.
import { ApolloClient, ApolloProvider, InMemoryCache} from '@apollo/client
function App({ Component, pageProps}) {
const client = new ApolloClient({
uri: "https://example.codecamp.co.kr/graphql",
cache: new InMemoryCache()
})
return (
<ApolloProvider client={client}>
<Component {...pageProps}/>
</ApolloProvider>
)
}
mutation을 사용하기 전, playground에서 우리가 사용하려는 mutation이 제대로 작동하는지 확인합니다.
만약, 제대로 작동한다면 GrahpQL mutation을 실행하려는 페이지 상단에서, apollo-client의 도구들을 불러옵니다.
// GraphQL 요청에 필요한 도구 불러오기
import { useMutation, gql } from '@apollo/client'
Javascript 입력 부분에 playground의 코드를 복사하여 아래와 같이 gql`` 사이에 붙여넣어 변수/상수를 만들어 줍니다.
// GraphQL 코드 생성
const CREATE_BOARD = gql`
mutation {
createBoard(
write: "훈이",
password: "1234",
title: "안녕하세요, 훈이에요",
contents: "반갑습니다"
) {
// return되는 값
message
}
}
`
위에서 만든 gql 변수/상수를 활용하여, useMutation을 만들어 줍니다.
createBoard는 mutation을 실행하기 위한 이름입니다.
따라서 aaa 등 아무 이름을 붙여도 상관없습니다.
// mutation 코드 생성
const [createBoard] = useMutation(CREATE_BOARD)
게시물 등록 버튼을 클릭했을 때 실행되는 함수에서 mutation 코드를 실행해 줍니다.
function handleClickPost() {
createBoard({
variables: {
aaa: "훈이",
bbb: "1234",
ccc: "안녕하세요, 훈이에요",
ddd: "반갑습니다"
}
})
return (
<button onClick={handleClickPost}>게시물 등록</button>
)
}
게시물이 정상적으로 등록되는지 확인해 줍니다.
하지만 위의 코드는 정적으로 항상 같은 게시물이 등록된다는 문제점이 있습니다.
이를 보완하기 위해서 3단계의 CREATE_BOARD 부분을 변경해야합니다.
GraphQL에 데이터는 최종적으로 등록하기 버튼을 눌렀을 때, 실행되는 handleClickPost 함수에서 실행되는 mutation에서 넣어줘야 합니다.
들어가는 데이터를 고정된 값에서 state로 변경하면 정적인 데이터에서 동적인 데이터로 변경이 됩니다.
Rest-API 또는 GraphQL-API를 사용해서 해야할 일은 요청에 대한 응답으로 받은 객체(JSON)을 변수에 담아서 사용하는 것 입니다.
여기서 응답 결과를 변수에 담아서 사용하려면 통신이 완료될 때까지 기다려야 합니다.
// mutation에 동기식 처리
async function handleClickPost() {
const result = await createBoard({
variables: {
aaa: "훈이",
bbb: "1234",
ccc: "안녕하세요, 훈이에요",
ddd: "반갑습니다"
}
})
// 결과 확인하기
console.log(result)
}
return (
<button onClick={handleClickPost}>게시물 등록</button>
)
기본 형식은 이렇게 됩니다. 화살표 함수로 사용할 때는 async의 위치를 () 앞에 입력해야 합니다.
// 비동기 통신
async function 함수명() {
// 서버에 요청하는 코드
}
// 동기 통신
async function 함수명() {
await // 서버에 요청하는 코드
}
// 화살표 함수의 경우
const 함수명 = async () => {
await // 서버에 요청하는 코드
}
네트워크 문제 해결방법
데이터 통신 과정이 생기면서 콘솔창에서는 확인할 수 없는 에러들이 발생합니다.
이러한 에러들은 개발자 도구의 [Network] 세션에서 확인할 수 있습니다.
Request, Response, Preview 헤더를 각각 확인하면서 어떤 문제가 발생하였는지 확인하고 수정할 수 있습니다.