도움말 - 글감 수집하기 (인용)

도움말 - 부분 리뷰 작성하기

3편: React + GraphQL + Flowtype으로 트렐로 클론 웹앱 만들기 - Trello Board 생성

우리는 이전 편에서 graphcool 서버를 만들었고, 기본적인 graphql에 대해 다뤘다. 이번 편에서는 트렐로의 보드를 만들어 볼 것이다.


참고: 이번 튜토리얼을 진행 하기 위해 진행 되는 코드를 깃헙에 업로드 해놨으니, 이 튜토리얼을 진행하고 싶다면 아래에서 소스를 클론 받은 후 아래의 내용을 따라가기를 추천 드립니다. 

튜토리얼 소스:

https://github.com/simsim0709/react-apollo-flow-trello-clone/tree/ch-3 

이전 편:

0편: React + GraphQL + Flowtype으로 트렐로 클론 웹앱 만들기 - 소개

1편: React + GraphQL + Flowtype으로 트렐로 클론 웹앱 만들기 - 프로토타입

2편: React + GraphQL + Flowtype으로 트렐로 클론 웹앱 만들기 - graphcool (GraphQL 서버 만들기)


이번편에서 다룰 내용은 아래와 같다:

  • graphql Board 타입(type)을 만든다.
  • playground(graphiql)로 Board 타입의 query, mutation을 테스트한다.
  • graphcool endpoint를 react-apollo를 사용하여 우리의 클라이언트 앱과 연결한다.
  • react-apollo의 graphql 함수를 사용하여 보드(Board) 데이터를 리스팅 한다.
  • 보드 생성 폼을 만들고, 이를 mutation과 연결 하여, 보드를 생성한다.

Board type 생성

소스를 체크아웃 받고, 프로젝트의 /graphcool-server/types.graphql을 열어 보면, 여기에 Board 타입이 추가 된 것을 볼 수 있다.

type Board @model {
id: ID! @isUnique
createdAt: DateTime!
updatedAt: DateTime!
name: String!
description: String
}

참조: 여기에 로 시작하는 것은 graphql의 directive이다. @model, @isUnique 는 graphcool 서비스에서 커스텀으로 만든 directive인데, @model 을 선언하면 이 타입이 데이터 모델이 되는 것이고, @isUnique  directive는 이 필드가 유니크 해야 한다는 것이다.

새로운 schema를 graphcool 서비스에 적용 하기 위해 graphcool 디플로이를 실행 한다:

graphcool deploy --force

playground에서 확인해보면 새로 추가된 보드 타입으로 query, mutation, subscription이 생긴걸 확인 할 수 있다.

Board query, mutation 테스트

우리가 적용한 Board 타입이 서버에 반영 되었으니 playground(graphiql)에서 query, mutation을 테스트 해 볼 것이다.

mutation

mutation CreateBoard($name: String!, $description: String) {
createBoard(name: $name, description: $description) {
id
name
}
}

위와 같이 입력 후 플레이 버튼을 누르면 생성된 아이디가 리턴 되는 것을 볼 수 있다:

query 

이렇게 생성된 데이터를 쿼리(query) 해보자:

query AllBoardsQuery {
allBoards {
id
name
description
}
}

그럼 이렇게 방금 mutation으로 생성 했던 데이터가 리턴 되는 것을 볼 수 있다:

몇개 더 테스트 겸 넣어 보고 쿼리를 해보면 추가된 데이터가 정상적으로 쿼리 되는 것을 확인 할 수 있다.

이제 우리가 새로 추가한 Board model이 정상 작동 되는걸 확인 했으니 우리 클라이언트 앱과 연결하여 우리의 앱에서 이것을 구현 해보자.

graphcool 백엔드와 클라이언트 앱 연결

apolloClient.js

apolloClient.js 파일을 열어보면 uri 값이 process.env에 세팅 한 값을 가져와서 연결 하는 것을 알 수 있다. 우리는 이 값을 .env.local 파일을 만들어서 여기에 api 주소를 추가 할 것이다. 

const client = new ApolloClient({
link: new HttpLink({ uri: process.env.REACT_APP_GRAPHCOOL_SIMPLE_API }),
cache: new InMemoryCache(),
});

위에 uri의 값을 graphcool의 endpoint중 simple API 값을 넣어 줄 것이다.(참고: 이 값이 기억나지 않는다면 graphcool console에 왼쪽 하단에 "ENDPOINTS" 버튼을 클릭하고 이중 "SIMPLE"을 클릭하면 나오는 값을 넣어주면 된다.).  

App.js

App.js를 열어 보면 루트 엘리먼트로 ApolloProvider로 감싸고 client prop에 apolloClient를 넣어 주었다. (리덕스 초기 세팅과 비슷하다고 생각하면 된다.)

이렇게 하면 graphcool  백엔드 서비스와 클라이언트 앱이 연결 된 것이다.

graphql-tag와 graphql 함수

graphql-tag

graphql-tag 패키지를 사용하여 우리가 playground(graphiql)에서 작성한 것처럼 graphql query 또는 mutation을 정의하는 데 사용 된다. 기본적인 사용법은 graphql-tag를 import하고, 이를 template literal과 조합하여 query 또는 mutation을 정의한다. 실제 사용은 아래에서 소스를 보면서 확인하자.

react-apollo의 graphql

react-apollo 패키지의 graphql 함수를 사용해서 실제로  우리가 graphql-tag패키지를 사용하여 정의 했던 데이터를 graphcool 서버에 요청 할 것이다.

pages/MainPage.js

기본적으로 graphql-tag를 사용하여 요청하는 데이터를 정의 하는 부분이다.(32번째 라인)

const ALL_BOARDS_QUERY = gql`
query AllBoardsQuery {
allBoards {
id
name
description
}
}
`;

실제로 서버에 데이터를 요청하고 data를 처리하는 부분이다(42번째 라인).

export default graphql(ALL_BOARDS_QUERY, {
props: ({ ownProps, data }) => {
return {
boardsData: data.allBoards,
};
},
})(MainPage);

graphql 함수를 통해 query 데이터를 요청하면, data 객체가  MainPage의 prop으로 추가된다. 하지만, 여기서 우리는 이 data 객체 중에 실제 보드 데이터(allBoards)만 MainPage 컴포넌트의 boardsData prop으로 보내도록 했다. 이렇게 선언하면, MainPage 컴포넌트는 boardsData를 prop으로 받게 된다. 

그리고 나서, MainPage  컴포넌트에 하드코딩 되어 있던 부분을 boardsData를 받아서 처리하도록 변경했다:

const MainPage = ({ boardsData }) => {
return (
<Page>
<Container>
{boardsData &&
boardsData.map(({ id, name, description }) => (
<Item key={id}>
<BoardItem name={name} description={description} />
</Item>
))}

<Item>
<BoardDialogButton />
</Item>
</Container>
</Page>
);
};

자 이제 화면을 확인해보면 좀전에 우리가 테스트로 넣었던 데이터가 리스팅 되는 것을 알 수 있다!

보드 생성 폼과 createBoard mutation

query를 통해 보드 데이터를 리스팅 했으니 이제 mutation을 진행해보자. 

먼저 리스트 마지막에 카드로 된 버튼을 만들고 이걸 클릭했을 때 보드를 추가 할 수 있는 폼을 다이얼로그로 만든다. 여기에 graphql mutation을 선언해서 데이터를 서버에 저장하도록 한다.

BoardDialogButton.js

const CREATE_BOARD_MUTATION = gql`
mutation CreateBoard($name: String!, $description: String) {
createBoard(name: $name, description: $description) {
id
name
}
}
`;
export default compose(withStyles(styles), graphql(CREATE_BOARD_MUTATION))(
BoardCreateButton
);

query에서와 동일하게 mutation도 graphql-tag 패키지를 통해 graphql을 선언한다. 다른점은 query대신에 mutation을 사용 한다는 것과 variables를 선언하여 그 값을 createBoard 필드에 매핑해주는 부분이 있다는 것이다.

BoardDialogButton 컴포넌트의  handleSubmit 메소드를 보면 this.props.mutate를 통해 name, description 값을 보내준다. 

handleSubmit = async () => {
try {
const result = await this.props.mutate({
variables: {
name: this.state.name,
description: this.state.description,
},
});
console.log('result', result);
} catch (error) {
console.error('error', error);
}
this.handleDialog();
};

정상적으로 데이터가 생성 되는지 확인하기 위해, 폼의 name과 description을 입력하고 ok를 눌러보자. 에러가 발생하지 않았지만 새로 생성한 보드가 페이지에 반영 되지 않는다. 페이지를 새로고침 해보자. 그러면 새로 추가된 보드가 추가 된것을 알 수 있다. 

 지금 이문제는 왜 생기는걸까?

이 문제는 다음 편에서 해결해보도록 하겠다. 

궁금하다면 여기를 확인해보자!


리뷰