본 포스트에서는 리액트를 이용하여 네이버 API로 데이터를 검색해서 목록 화면을 구성해 보겠습니다.
저번 포스팅까지 해서 뉴스와 도서 목록을 각각 구성해서 UI까지 만들어 보았습니다. 지금은 뉴스와 도서를 번갈아가며 조회하려면 소스코드를 수정해가면서 조회해야 합니다. 이번 포스팅에서는 [뉴스]와 [도서] 탭을 만들어서 각 탭을 선택하면 원하는 목록이 조회되도록 해보겠습니다.
01. Concept 포스트에서 이야기한대로 탭은 화면 하단에 아래와 같은 모양으로 만들어 보겠습니다.
/src/component/ 하위에 tablist.component.jsx 파일을 하나 생성합니다. 이 파일에 탭을 구성하여 보겠습니다. 먼저 탭 한 칸에 대한 컴포넌트를 만들어 보겠습니다.
Tab 이라는 이름의 class를 생성하고 props를 전달 받습니다. return 하는 UI는 단순합니다. <li> 아래 실제 연결 동작을 담당할 <anchor> 태그를 하나 생성하고 id 속성을 부여합니다. 탭의 초기 구성을 위해 props로 전달 받은 on 속성에 따라 className 속성을 부여합니다.
그리고 탭을 선택했을 경우에 동작을 담당하는 changeTab 이라는 함수를 만들고 onClick 속성에 할당합니다. UI 에 표시되는 텍스트는 props로 전달 받은 tabName을 표시합니다.
changeTab 함수에서 현재 하는 동작은 on/off 에 대한 class만 변경합니다. 현재 on class가 붙어 있는 <a> 태그에서 on class를 제거하고 현재 입력 받은 탭에 on class를 추가합니다.
다음엔 Tab 컴포넌트를 사용해 전체 탭을 표시하는 TabList 컴포넌트를 아래와 같이 작성합니다.
먼저 tabList 배열을 하나 생성하고 표시할 탭 목록을 작성합니다. 우리는 "뉴스"와 "도서" 두 개의 탭을 사용할 것이므로 두 개를 만들고 초기에는 뉴스 탭을 활성화 시키기위해 뉴스 탭에는 on: true 로 세팅합니다. UI에 Rendering 할 부분은 <ul> 태그 아래 <Tab> 컴포넌트를 넣어 줍니다.
import React from 'react';
import ReactDOM from 'react-dom';
import App from './app.js';
ReactDOM.render(<App />, document.getElementById('app'));
이제 TabList UI에 사용할 stylesheet를 "대강" 추가합니다. main.css 파일에 추가하면 됩니다.
.tabBox{position:fixed;bottom:0px;width:100%;height:50px;border-top:1px solid #DDD;background-color:#FFF;}
.tabList{display:table;width:100%;table-layout:fixed;}
.tabList li{display:inline-block;text-align:center;width:49%;}
.tabList li:first-child{border-right:1px solid #DDD;}
.tabList li a{display:block;color:#000;font-size:1.6rem;line-height:48px;}
.tabList li a span{display:inline-block;padding:0px 8px;width:100%;}
.tabList li a.on span{background-color:#999;color:#FFF;font-weight:700;}
여기까지 작성했으면 일단 동작은 되지 않겠지만 UI는 확인할 수 있습니다. UI를 확인해보면 아래와 같습니다.
[뉴스]와 [도서] 탭을 선택하면 아래와 같이 토글이 되는 것을 확인할 수 있습니다.
탭 토글까지 확인되었으면 이제 탭 선택에 따라 뉴스, 도서가 인터페이스 되도록 개발해 보겠습니다. 탭을 선택할 때 선택한 탭에 맞는 데이터를 인터페이스 하려면 ListView 컴포넌트가 현재 선택한 탭이 무엇인지를 알아야 합니다. 이렇게 컴포넌트에서 다른 컴포넌트 등과 데이터나 상태를 공유할 때 React에서는 React Redux, Context API, Recoil 등의 상태 관리를 사용합니다.
이제 Tab 컴포넌트에서 selectedTabId atom을 사용하여 상태를 변경하고, 변경된 상태를 참조하여 탭의 UI를 변경하겠습니다. 먼저 탭의 상태를 변경할 수 있도록 useRecoilState Hook을 선언합니다. useRecoilState Hook은 useState Hook과 유사한 방법으로 사용할 수 있습니다.
그 다음 탭을 Rendering 하는 부분에서 이 상태 변경을 이용해서 탭의 현재 상태를 변경하도록 합니다. 변경 전은 컴포넌트 생성 시에 props를 전달 받아 UI를 변경하거나, 탭을 선택할 때 JavaScript로 해당 Element의 class 속성을 변경하는 방법을 사용했었는데 변경 후에는 현재 atom에 저장된 값과 각 탭 아이디가 일치하는지를 확인해서 on/off 처리해 보겠습니다.
changeTab 함수에서는 RecoilState에 저장한 tabId를 변경하도록 setSelTabId 함수만 호출합니다. UI를 Rendering 할 때 해당 탭의 아이디와 저장한 selTabId를 비교하여 동일한 탭일 경우 "on" class를 부여하고, 다른 탭일 경우에는 부여하지 않습니다.
TabList 컴포넌트에서는 탭 목록 선언 시에 on 항목을 삭제합니다. (상태 값을 참조하는 것으로 변경하였으므로 해당 값은 더 이상 사용하지 않습니다.) 변경한 tablist.component.jsx 파일의 소스코드는 아래와 같습니다.
본 포스트에서는 리액트를 이용하여 네이버 API로 데이터를 검색해서 목록 화면을 구성해 보겠습니다.
저번 포스트에서 Naver News API를 호출해서 아래 형태로 결과를 받아보는 부분까지 진행해 보았습니다.
인터페이스 결과 데이터의 형태를 확인했으니, 이제 ListView의 UI를 만들어 보겠습니다.
ListView 컴포넌트가 Rendering 할 HTML은 아래와 같이 <ul> 태그만 하나 생성해서 return 한 상태입니다. News API를 호출하여 받은 데이터를 <ul> 안에 <li>로 반복해서 넣어주면 될 것 같지만, <li> 내부에도 여러 태그와 데이터를 바인딩하는 부분이 있을 것이고, 뉴스일 경우와 도서일 경우를 분리해서 <li>를 구성해야 합니다.
하여 <li> 부분은 별도의 컴포넌트로 작성하겠습니다. 일단 NewsRow 컴포넌트를 아래와 같이 작성합니다.
props로 넘어오는 데이터가 위와 같은 형태이고 row라는 이름으로 전달하도록 하겠습니다. 우리는 이 데이터 중 title(제목), pubDate(작성일시), description(요약) 3가지 데이터를 사용하겠습니다. 이 중 pubDate는 momentJs 모듈을 사용하여 YYYY.MM.DD HH:mm 형식으로 변환해 줍니다.
그리고 NewsRow의 return 에는 위의 내용과 같이 Rendering 할 HTML을 작성합니다. 작성하는 내용 중 특이한 부분이 있습니다. JavaScript에서는 innerHTML로 사용하던 부분을 React에서는 dangerouslySetInnerHTML을 사용하여 표현합니다. 관련된 짧은 설명이 React 공식 페이지에 있으므로 아래 링크를 참고하시면 됩니다.
여기까지만 변경을 하면 위에서 작성한 NewsRow stylesheet가 반영되어 아래와 같이 UI가 만들어 집니다. (이..이미지가 깨지는 게시물도 있네요)
BookRow에 사용할 stylesheet도 main.css에 추가해 줍니다.
.listView li .bookImg{position:relative;float:left;}
.listView li .bookDesc{float:left;width:100%;}
.listView li a.bookRow{padding:0px 10px 0px 100px;display:block;height:auto;}
.listView li a.bookRow .bookImg{margin-left:-100px;margin-top:10px;}
.listView li a.bookRow .cont span.author{margin-bottom:8px;color:darkblue;}
좌측에 도서 이미지를 배치하고 오른쪽에 제목, 저자, 요약 내용을 배치 했습니다.
이번 포스트는 여기까지 작성해 보겠습니다. NewsRow와 BookRow 컴포넌트를 포함하고 있는 listview.component.jsx 프로그램의 현재까지의 소스는 아래와 같습니다.
본 포스트에서는 리액트를 이용하여 네이버 API로 데이터를 검색해서 목록 화면을 구성해 보겠습니다.
저번 포스트에서는 간단하게 "Hello World"를 출력하는 프로그램을 작성하고 실행시켜서 확인해 보았습니다. 이번 포스트에서는 현재 과정의 주 목적인 ListView를 구성하기 위해 Naver News API를 호출해서 데이터를 확인해보는 과정까지 개발해 보겠습니다.
js, jsx 파일은 /src 아래 경로에 작성하면 됩니다.
먼저 /src 하위에 /component 라는 폴더를 만들고 listview.component.jsx 파일을 하나 생성하고 아래 설명을 참고하여 목록 컴포넌트를 작성해 봅니다. 중간중간 코드에 추가한 부분은 아래와 같이 블럭으로 표시하겠습니다.
//ADD :: START
추가한 코드
//ADD :: END
먼저 컴포넌트를 생성하고, 현재 컴포넌트는 목록 컴포넌트이므로 데이터를 조회할 때마다 상태를 변경하고 목록을 갱신하기 위해 useState Hook을 사용하여 상태를 선언하고 초기 값은 null로 설정합니다.
apiGet 함수는 type과 param을 전달 받도록 작성했습니다. type은 뉴스(news)인지 도서(book)인지를 결정하는 인자이고, param은 검색어입니다. 두 인자를 받아서 Naver API URL을 조립하고 GET 방식으로 호출합니다. 이 때 Naver Open API 규격에 따라 headers에 인증 정보를 전달합니다.
Ajax는 비동기지만 aync/await를 사용했으므로 동기처럼 사용할 수 있습니다. 조회를 하고 나면 컴포넌트의 상태를 변경해 줍니다. 위에서 선언한 setArticles 함수를 사용해서 조회한 결과로 상태를 변경합니다.
다음은 useEffect Hook을 사용하여 컴포넌트가 마운트 될 때 한 번만 실행할 수 있도록 두 번째 인자로 빈 배열([])을 넘겨 아래와 같이 작성합니다. "코스피"라는 단어가 들어가는 뉴스를 검색하기 위해 아래와 같이 작성해 봅니다.
여기까지 작성했다면 일단 ListView 컴포넌트는 대강 작성했습니다. 이제 main.js 에서 ListView 컴포넌트를 사용하도록 아래와 같이 변경합니다.
import React from 'react';
import ReactDOM from 'react-dom';
import ListView from './component/listview.component.jsx';
ReactDOM.render(<ListView />, document.getElementById('app'));
이제 실행을 한 번 시켜봐야 하는데, <ListView /> 등의 JSX 요소는 React의 컴포넌트를 표현하는 확장된 형태일 뿐, 정규 HTML 문법이 아니기 때문에 브라우저가 해석을 할 수 없습니다. 브라우저가 이해할 수 있는 순수 JavaScript로 변환하는 과정인 transpile 이라는 과정을 거쳐야 하며, 이 과정은 babel을 사용해서 진행합니다.
본 포스트에서는 리액트를 이용하여 네이버 API로 데이터를 검색해서 목록 화면을 구성해 보겠습니다.
저번 시간에는 프로젝트 경로를 생성하고 개발에 필요한 모듈들을 설치해 보았습니다. 설치하는 과정에서 의존성에 대해서도 잠시 알아보았습니다. 이번에는 VSCode에 프로젝트를 반입해서 프로젝트 구조 및 보일러 플레이트 코드를 작성한 후 간단하게 "Hello World"를 출력해보겠습니다.
VSCode로 프로젝트 열기
먼저 빈 VSCode 창을 하나 열고 [폴더 열기] 버튼을 클릭합니다.
만들어 둔 searchNaverApi 폴더를 선택하여 엽니다.
해당 폴더를 선택하면 VSCode에 프로젝트가 아래와 같이 반입됩니다.
프로젝트 구조 생성
프로젝트 하위에 폴더를 두 개 만들어 보겠습니다.
[./public]
public 이라는 폴더에는 html, css, image 등 정적인 Resources를 관리합니다.
[./src]
src 라는 폴더에는 React 기반으로 개발하는 JavaScript 소스 코드를 관리합니다.
먼저 public 폴더를 생성하고 하위에 index.html 파일을 생성하고 아래와 같이 작성합니다. html 파일에는 별 내용은 없으며 React 모듈을 초기화 할 main.js 파일을 포함하는 부분과 React 애플리케이션을 Rendering 할 "app"라는 아이디를 가진 div를 하나 선언합니다.
JavaScript 애플리케이션의 Package 의존성을 관리하기 위해 npm이나 yarn을 사용합니다. npm이나 yarn은 Node.js 기반으로 동작하므로 Node.js 인스톨러를 다운로드하여 설치합니다. 아래의 링크에서 각자의 환경 (Windows, MAC)에 맞는 버전을 다운로드 받아서 설치하시면 됩니다.
Yarn까지 설치했다면 프로젝트 루트로 사용할 workspace를 하나 생성합니다. 각자가 편한 경로에 디렉토리 하나를 생성하시면 됩니다. NAVER API를 통해 간단한 검색을 하는 프로그램이므로 searchNaverApi라고 명명하겠습니다.
workspace 하위에 아래 디렉토리를 생성하고 이동합니다.
mkdir searchNaverApi
cd searchNaverApi
해당 디렉토리에 프로젝트 설정 파일을 생성합니다. 프로젝트 설정 파일은 package.json이며 yarn init 명령을 수행해서 생성하시면 됩니다. yarn init 명령을 입력하면 아래 정보를 입력하라고 나오는데, 성실하게 입력하셔도 되고, 나중에 파일 생성 후 변경도 가능하니 그냥 모두 Enter로 넘어가셔도 상관 없습니다.
D:\workspace\searchNaverApi> yarn init
name (searchNaverApi) :
version (1.0.0) :
description :
entry point (index.js) :
repository url :
author :
license (MIT) :
private :
일단 모두 입력 or skip 하게 되면 프로젝트 하위 경로에 package.json 파일이 하나 생성됩니다.
기본 설정으로 만들고 싶을 경우 yarn init -y 명령으로 생성하면 별도 질문 없이 package.json이 기본 설정으로 생성됩니다.
현재까지 진행한 프로젝트 파일 구조는 아래와 같습니다.
searchNaverApi
└── package.json
모듈 설치
현재 프로젝트 개발에 필요한 모듈들을 설치합니다. 각 모듈의 버전 별로 호환성 문제나 코드가 상이할 수 있으므로 설치할 버전을 지정하여 설치하겠습니다.
모듈을 설치할 때는 yarn add 명령으로 설치합니다. yarn add 명령의 형식은 아래와 같습니다.
yarn add [packages ...][flags]
yarn help 명령을 입력하면 flags에 대한 상세한 내용을 조회할 수 있지만 이번에는 의존성에 대한 부분만 간략하게 보고 넘어가겠습니다. yarn help add 명령으로 조회한 설명은 아래와 같습니다.
D:\workspace\searchNaverApi> yarn help add
...
-D, --dev save package to your `devDependencies`
-P, --peer save package to your `peerDependencies`
-O, --optional save package to your `optionalDependencies`
...
위 내용 중 --dev (개발 의존성)와 아무것도 입력하지 않았을 경우인 일반 의존성으로만 구분하여 설치를 진행하겠습니다. 간단하게 일반 의존성은 런타임에서 사용하는 모듈을 설치할 때 사용하고, 개발 의존성 (--dev)은 빌드 타임 (babel이나 webpack 등 개발 workflow에서 사용)에서만 사용하는 모듈을 설치할 때 사용합니다.
기본적인 React package 및 compile, bundling을 위한 도구를 설치하는 과정입니다. react 및 react-dom을 제외하고는 런타임에 필요한 모듈이 아니므로 개발 의존성으로 설치합니다. 개발 시에 필요한 모듈은 추가적으로 날짜 formatting을 위해 moment 정도만 설치합니다.
(나중에 추가적으로 필요한 모듈이 있으면 그때그때 설치하면 됩니다.)
yarn add moment@2.29.1
설치를 한 모듈은 package.json 파일에서 의존성 관리를 합니다. 설치를 완료한 후 package.json 파일을 확인해 보면 아래와 같이 개발 의존성으로 설치한 모듈들은 devDependencies 하위에, 일반 의존성으로 설치한 모듈들은 dependencies 하위에 관리되고 있음을 알 수 있습니다.