[code.camp_4일차]동기/비동기,ApolloClient

남예지·2022년 11월 3일
0

code.camp

목록 보기
5/5

동기와 비동기방식


등록된 글을 불러올 때 컴퓨터가 불러오는 시간이 아무리 빨라도(1ms라도) 조금은 걸리는데 이때 오류가 생길 수 있다. 그래서 데이터가 백앤드 컴퓨터에 갔다올때까지 기다려주는 명령어가 필요하다.

그림으로 표현하면 위와 같다.

그럼 비동기는 언제 쓸까
요청들이 서로 기다릴 필요가 없을때 쓴다.
어떤 경우일까?

  • 동시에 여러 일을 할 때(웹페이지 컨텐츠같은 것들, 먼저 받아온 것부터 보여주자!)

하지만, 우리가 이전에 게시글 등록 후 불러왔을 때 게시글이 불러와지지 않는 오류에 직면한 것처럼 비동기 실행 방식이 아닌 다른 통신 방식을 사용해야할 경우가 있다. 이러한 경우에 사용하는 것이 동기 실행 방식이다.

  • 동기 실행: 서버 컴퓨터의 작업이 끝날 때까지 기다린 후 다음 작업을 실행하는 통신이다.

동기 실행 방식은 등록 요청을 하게 되면 등록 과정이 모두 완료될 때까지 기다려준 후 게시글 불러오기 과정이 실행되기 때문에 문제 없이 작업이 가능하다.

VSCODE에서 비동기

자바스크립트는 동기적 방식(위에서 한 줄 한 줄), 하지만 axios같이 추가로 추가하는 외부 라이브러리 같은 경우 보통 비동기적으로 작동한다. await를 붙여 동기로도 작동할 수 있다.
만약 비동기로 데이터를 요청하고 바로 출력하면 Promise라는 약속을 준다. (언젠진 모르겠지만 주긴 줄거야)

const data = axios.get('https://koreanjson.com/posts/1')
// axios는 비동기이므로 koreanjson에 데이터를 요청해서 가져온다.
console.log(data)  // Promise
// axios가 데이터를 가져오기 전에 console이 실행되기 때문에 promise(약속)만 받은 상태이다.

axiox 앞에 await를 붙이면 동기적으로 활용이 가능하다.
await를 사용하려면 규칙이 하나 있다.
변수를 함수로 감싸고 함수 앞에 async를 붙여줘야 한다.

async/await 는 비동기를 동기로 바꿔주는 명령어로 짝꿍이다.

rest-API -vscode 실습

// axios가 깔려있을때, axios 사용하기 위해 불러오기 import
import axios from "axios";

export default function RestGetPage() {
//비동기
  function onClickAsync() {
    const result = axios.get("https://koreanjson.com/posts/1");
    console.log(result); //Promise
  }
//동기  => async / await  사용
  async function onClickSync() {
    const result = await axios.get("https://koreanjson.com/posts/1");
    console.log(result); //제대로 된 결과 => {title...}
  }

  return (
    <div>
      <button onClick={onClickAsync}>Rest-API(비동기) 요청하기</button>
      <button onClick={onClickSync}>Rest-API(동기) 요청하기</button>
    </div>
  );
}

결과값은 아래와 같다.

실수에서는 function을 잘 사용하지 않습니다.
호이스팅 문제와 중복선언 문제때문이다.
var 같은 옛날 문법은 호이스팅이 되는데 문제가 중복선언이 가능해서 먼저 선언한게 삭제가 됨 이때 function도 같이 만들어졌다.
그래서 function도 같은 이름으로 선언하면 먼저 선언한게 var처럼 삭제가 된다.
const , let이 나오면서 함수도 const로 만들기 시작했다.
const ggg = function(){} 이렇게 함수를 선언하면 상수이기 때문에 중복 선언이 발생하지 않아 문제가 되지 않는다.
*최근에는 next.js에서 이런 문제를 방지하게끔 만들었지만, 다른 문제들도 미연에 방지하고자 화살표함수로 많이 사용한다.

  const onClickAsync = () => {
    const result = axios.get("https://koreanjson.com/posts/1");
    console.log(result); //Promise
  };
  
  // **화살표함수로 사용 시 async는 ()앞에 써준다.**
  const onClickSync = async () => {
    const result = await axios.get("https://koreanjson.com/posts/1");
    console.log(result); // 제대로 된 결과 => {title...}
  };
}

VSCODE graphql 기초

apollo-client 셋팅하기

playground 에서 실습했던 내용의 코드를 vscode에서 적용하기 위해서는 apollo-client라는 도구가 필요하다.

graphql은 apollo-client를 설치해야한다.
터미널에 아래와 같이 입력해주면 package.json에 뜬다.

npm install @apollo/client graphql


설치가 다 되었다면 apollo-client 를 셋팅해준다.

import {ApolloClient, ApolloProvider, InMemoryCache} from '@apollo/client'
function MyApp({ Component, pageProps }){
	const client = new ApolloClient({
		uri: "http://example.codebootcamp.co.kr/graphql",
		cache: new InMemoryCache()
	})
	return (
		<ApoloProvider client={client}>
			<Component {...pageProps}/>
		</ApolloProvider>
	)
}

app.js에 이렇게 해줘야 모든 js페이지에서 graphql을 사용할 수 있다.

playground 코드를 vscode에서 쓰려면...


CREATE_BOARD에 graphql-API를 넣고 useMutation한 값을 실행 함수에 넣은 뒤 함수를 필요한 곳에서 실행하면 그때 API를 가져온다.

import {gql, useMutation} from '@apollo/client'

const 나의그래프큐엘셋팅 = gql`
    mutation{
        createBoard(writer: "123", title: "제목입니다~~", contents: "내용이에요!!!"){
            _id
            number
            message
        }
    }
`

export default function GraphqlMutationPage(){
    const [나의함수] = useMutation(나의그래프큐엘셋팅)

// axios처럼 나의함수도 비동기이므로 동기 작동을 위해 async/await를 붙인다.
    const onClickSubmit = async () => {
        const result = await 나의함수()
        console.log(result)
    }

    return (
        <button onClick={onClickSubmit}>GRAPHQL-API(동기) 요청하기</button>
    )

}

디버깅

  1. 처음부터 습관을 들일 때 개발자도구에서 바꿔보고 원하는 모양이 나왔을 때 vscode 가서 수정하기.
  2. 디버깅 시 html, css 오류는 엘리먼트, js오류는 콘솔, network오류는 네트워크(api가 안될때)
  • 네트워크에 preflight는 먼저 한번 날려보는 가짜 API기 때문에 문제가 있는지 먼저 보는 것. (가짜 요청...)
  • 디버깅은 일부로 틀리고 고치고를 하면 실력이 많이 늘어난다고 하니 앞으로 많이 해봐야겠다. 잘하는 개발자는 문제가 생겼을 때(모르는게 있거나 에러가 발생했을 때) 해결 속도가 빠르다.
    docs를 읽어보거나 자신만의 노하우로 검색을 하는 등 => 트러블슈팅이라 한다. 실력이 뛰어나면 트러블슈팅만 전문적으로 하거나 프로젝트 구조설계(아키텍트)를 하는 전문가들도 많다.
    실력이 성장하려면 검색과 docs를 많이 해봐야한다.

VSCODE graphql 심화

uri / url / urn

사실 url보다는 전체를 지칭하는 uri가 맞을 수도 있다.
뒤에 #aaa 는 스크롤 위치를 말하는데 이 아이디값을 footer에 위치한 id값 #footer로 넣으면 접속하자마자 footer로 내려가는걸 볼 수 있다.

graphql-API 원하는 데이터만 가져오기

createBoard

const 나의그래프큐엘셋팅 = gql`
 mutation {
   createBoard(
     writer: "123"
     title: "제목입니다~~"
     contents: "내용이에요!!!"
   ) {
     _id
     number
     message
   }
 }
`;
export default function GraphqlMutationPage() {
 const [나의함수] = useMutation(나의그래프큐엘셋팅);

 const onClickSubmit = async () => {
   const result = await 나의함수();
   console.log(result);
 };
 return (
   <div>
     <button onClick={onClickSubmit}>GRAPHQL-API(동기) 요청하기</button>
   </div>
 );
}

위 처럼 하드코딩으로 먼저 값을 넣어 잘 작동되는지 playground에서 확인해보고 아래와 같이 변수로 설정해 input한 값을 받아서 API를 통해 저장한다.

import { gql, useMutation } from "@apollo/client";
import { useState } from "react";

//세팅은 밖에다 해야한다. 함수 소속이 되기 때문에 별개로 ,
//백틱 안에다 작성/ 플레이 그라운드에서 가져옴
const 나의그래프큐엘셋팅 = gql`
  mutation createBoard($writer: String, $title: String, $contents: String) # 변수의 타입을 적는 곳 { 
    createBoard(writer: $writer, title: $title, contents: $contents) # 실제 우리가 전달할 변수 적는 곳 {
      _id
      number
      message
    }
  }
`;
export default function GraphqlMutationPage() {
  const [writer, setWriter] = useState("");
  const [title, setTitle] = useState("");
  const [contents, setContents] = useState("");
  const [나의함수] = useMutation(나의그래프큐엘셋팅);
  const onClickSubmit = async () => {
    const result = await 나의함수({
      variables: {
        //variables 이게 $ 역할을 함
        writer: writer,
        title: title,
        contents: contents,
      },
    });
    console.log(result);
  };
  const onChangeWriter = (event) => {
    setWriter(event.target.value);
  };
  const onChangeTitle = (event) => {
    setTitle(event.target.value);
  };
  const onChangeContents = (event) => {
    setContents(event.target.value);
  };
  return (
    <div>
      작성자: <input type="text" onChange={onChangeWriter} />
      제목: <input type="text" onChange={onChangeTitle} />
      내용: <input type="text" onChange={onChangeContents} />
      <button onClick={onClickSubmit}>GRAPHQL-API(동기) 요청하기</button>
    </div>
  );
}
  • 인자를 변수로 바꿔주어야 한다. 2번째 사진에 화살표처럼 나중에 인풋창에 입력한대로 이 $ 안에 들어간다.
  • 이 $달러 표시를 variavles라고 한다.
  • 값을 받아줄 input과 연결된 state를 넣는다.

createProduct

import { gql, useMutation } from "@apollo/client";
import { useState } from "react";
const MY_PRODUCT = gql`
  mutation createProduct(
    $seller: String
    $createProductInput: CreateProductInput!
  ) {
    createProduct(seller: $seller, createProductInput: $createProductInput) {
      _id
      number
      message
    }
  }
`;
export default function GraphqlCreateProduct() {
  const [myProduct] = useMutation(MY_PRODUCT);
  const [seller, setSeller] = useState("");
  const [name, setName] = useState("");
  const [detail, setDetail] = useState("");
  const [price, setPrice] = useState("");
  const onClickProduct = async () => {
    const result = await myProduct({
      variables: {
        seller: seller,
        createProductInput: {
          name: name,
          detail: detail,
          price: Number(price),
        },
      },
    });
    console.log(result);
  };
  const onChangeSeller = (event) => {
    setSeller(event.target.value);
  };
  const onChangeName = (event) => {
    setName(event.target.value);
  };
  const onChangeDetail = (event) => {
    setDetail(event.target.value);
  };
  const onChangePrice = (event) => {
    setPrice(event.target.value);
  };
  return (
    <div>
      판매자: <input type="text" onChange={onChangeSeller} />
      제품정보:
      <div>
        제품이름: <input type="text" onChange={onChangeName} />
        제품상세: <input type="text" onChange={onChangeDetail} />
        제품가격: <input type="text" onChange={onChangePrice} />
      </div>
      <button onClick={onClickProduct}>[ GRAPHQL-API 요청하기 ]</button>
    </div>
  );
}

스코프체인

스코프 체인(Scope Chain)은 일종의 리스트로서 전역 객체와 중첩된 함수의 스코프의 레퍼런스를 차례로 저장하고, 의미 그대로 각각의 스코프가 어떻게 연결(chain)되고 있는지 보여주는 것을 말한다.

함수 안쪽에 찾는 변수가 있다면 현재 스코프 안에서 가져오고 함수의 안쪽에 없다면 바깥쪽 함수에서 찾는걸 스코프체인이라고 한다.

profile
총총

0개의 댓글