본문 바로가기

WINK-(Web & App)/React.js 스터디

[2024 React.js 스터디] 류상우 #7주차

반응형
4-1. API 연동의 기본

.우선 api-integrate 라는 이름의 새로운 프로젝트를 만들고 라이브러리인 axios 를 설치한다.

yarn add axios

 

axios를 사용해서 REST API 형태를 구성할 수 있다.

REST API 란 웹이 서로 상호작용할 수 있게 하는 것으로, 자원은 URL로 식별하고 메서드를 사용하여 원하는 작업을 실행할 수 있다.

  • 메서드 목록
    • GET: 데이터 조회
    • POST: 데이터 등록
    • PUT: 데이터 수정
    • DELETE: 데이터 제거
    • e.t.c.: PATCH, HEAD 등의 메서드도 있다.

axios 의 사용법은 다음과 같다.

import axios from 'axios';
axios.post('/users/1', {
    username: 'blabla',
    name: 'blabla'
});

axios. 뒤에 메서드를 소문자로 작성하고, 첫번째 파라미터에 API의 주소를 넣는다.

axios.post() 로 데이터를 등록 할 때에는 두 번째 파라미터에 등록할 정보를 넣을 수도 있다.

 

실습을 위해 예전에 활용신청을 해두었던 neis OPEN API 를 사용해보도록 하겠다.


useState 와 useEffect 로 데이터 로딩하기

 

useState 를 사용하여 요청 상태를 관리하고 useEffect 를 사용하여 컴포넌트가 렌더링될 때 요청을 시작하는 작업을 해보자.

 

요청에 대한 상태를 관리 할 때에는 다음 3가지 상태를 관리해주어야한다.

  • 요청의 결과
  • 로딩 상태
  • 에러

24.06.30 의 모교 급식을 불러와보았다.

예제로 나와있는 코드를 조금 수정하여 작성해보았다.

 

위 코드를 잠깐 살펴보자.

  • 콜백함수 내부에서 async 를 사용하는 새로운 함수를 선언한 이유는 useEffect 에 첫번째 파라미터로 등록하는 함수에는 async 를 사용 할 수 없기 때문이다.
    • async: function 앞에 async를 붙여 줌으로서 비동기적인 함수임을 알린다.
    • 비동기 작업: 코드가 완전히 끝날 때까지 기다리지 않고 나머지 코드를 실행하는 것이다.
  • axios.get() 에서 params를 파라미터로 지정하는 이유는 데이터를 요청할 때 추가적으로 필요한 정보를 전달하기 위해서이다. 원래는 URL에 필요한 정보를 포함하여 작성해야 하는데, params를 파라미터로 지정하면 axios에서 자동으로 URL에 추가해준다.
    • DATA 객체의 각 요소가 뜻하는 내용은 neis open API 를 참고하면 된다.
  • meals를 response.data 로 설정하는 이유는 setMeals(response)로 작성할 시, meals.data에 접근할 수 없기 때문인데 왜 그렇게 되는 지는 찾지 못했다.

데이터를 렌더링하기 전에 콘솔에 데이터를 출력하여 필요한 데이터의 경로를 찾아준다.

 

이후 찾은 경로를 토대로 렌더링할 문자열을 찾고, 그 문자열을 변환하여 렌더링 해준다.

 

 

데이터를 불러오기 전 LOADING..이 출력되는 것과 URL을 https://jsonplaceholder.typicode.com/users/showmeerror  로 변경했을 때 ERROR!! 가 출력되는 것도 확인할 수 있다.


API 재요청하기

 

버튼을 눌러서 API를 재요청하기 위해서는 useEffect의 파라미터로 있던 fetchMeals 함수를 밖으로 꺼내준 후, 버튼을 만들어 해당 함수를 연결해주면 된다.

추가로 문자열의 괄호와 괄호 안의 문자열을 지워주었다.

 

 

 

여기에 앞에서 배웠던 내용을 활용하여 코드를 다음과 같이 수정해주면

이렇게 입력한 날짜의 급식정보를 불러올 수 있다.


1. 라우팅이란?

라우팅은 사용자가 요청한 URL에 따라 알맞는 페이지를 보여주는 것을 의미한다.

 

예를 들어 블로그는 글쓰기 페이지, 포스트 목록 페이지, 포스트 읽기 페이지 등 여러 페이지로 구성되어있는데 이렇게 여러 페이지로 이루어진 웹 애플리케이션의 각 페이지별로 컴포넌트를 분리해가면서 프로젝트를 관리하기 위해 필요한 것이 라우팅 시스템이다.

 

리액트에서 라우터 시스템을 구축하기 위해 사용할 수 있는 크게 다음 두 가지가 있다.

  • 리액트 라우터: 이 라이브러리는 컴포넌트 기반으로 라우팅 시스템을 설정할 수 있다.
  • Next.js: Next.js는 리액트 프로젝트의 프레임워크로 리액트 프로젝트 설정, 라우팅 시스템, 최적화, 다국어 시스템 지원, 서버 사이드 렌더링 등 다양한 기능을 제공한다. 이 프레임워크의 라우팅 시스템은 파일 경로 기반으로 작동한다.

이 중에서 리액트 라우터를 사용해 싱글 페이지 애플리케이션을 만들어보자.


2. 싱글 페이지 애플리케이션이란?

싱글 페이지 애플리케션이란 말 그대로 한 개의 페이지로 이루어진 애플리케이션이다.

라우팅은 여러 페이지로 구성된 웹 애플리케이션을 관리하기 위한 것인데 왜 싱글 페이지 애플리케이션이라고 불릴까?

이를 이해하기 위해서는 싱글 페이지 애플리케이션 이전에 사용되던 멀티 페이지 애플리케이션에 대해 알아보아야 한다.

 

멀티 페이지 애플리케이션은 사용자가 다른 페이지로 이동할 때 새로운 html을 받아오고, 페이지를 로딩할 때마다 서버에서 리소스를 전달받아 화면에 보여 주었다.

정적인 페이지들은 이 방식이 적합하지만, 사용자 인터랙션이 많은 모던 웹 애플리케이션은 이 방식이 적합하지 않았다. 새로운 페이지를 보여줄 때마다 서버가 모든 준비를 부담하게 되면 트래픽이 더 많이 나오기 때문이다.

 

그래서 리액트 같은 라이브러리를 통해 필요한 부분만 자바스크립트를 사용하여 업데이트하는 방식을 사용하게 된 것이다.

이렇게 html은 한 번만 받아와서 웹 애플리케이션을 실행시킨 후에 필요한 데이터만 받아와서 화면에 업데이트 해주는 것이 싱글 페이지 애플리케이션이다.

 

싱글 페이지 애플리케이션은 본질적으로는 한 페이지만 존재하지만, 마치 여러 페이지가 존재하는 것처럼 느낄 수 있게 한다. 라우팅 시스템은 주소창의 경로에 따라 알맞는 페이지를 보여주는데, 이 때 링크를 눌러 다른 페이지로 이동할 때 다른 페이지의 html을 요청하는 것이 아니라, 주소창의 값만 변경하고 기존 웹 애플리케이션을 그대로 유지하면서 또 다른 페이지를 보여주게 되는 것이다.


3. 리액트 라우터 적용 및 기본 사용법

이제 리액트 라우터를 사용해 보자.

다음 순서로 진행된다.

  1. 프로젝트 생성 및 라이브러리 설치
  2. 페이지를 만들고 이동해보기
  3. URL 파라미터와 쿼리스트링 사용해보기
  4. 중첩된 라우트 구현하기
  5. 리액트 라우터의 부가기능 사용해보기

3-1. 프로젝트 생성 및 라이브러리 설치

우선 새로운 리액트 프로젝트를 생성하고, 리액트 라우터 라이브러리를 설치한다.

여기서는 npx가 아닌 yarn을 사용해 리액트 프로젝트를 생성하였다.

yarn create react-app router-tutorial
cd router-tutorial
yarn add react-router-dom

3-2. 프로젝트에 라우터 적용

프로젝트에 리액트 라우터를 적용하려면 src/index.js 에서 react-router-dom에 내장되어있는 BrowserRouter 라는 컴포넌트를 사용하여 감싸면 된다.

애플리케이션에 HTML5의 History API를 사용하여 페이지를 새로 불러오지 않고도 주소를 변경하고 현재 주소의 경로에 관련된 정보를 리액트 컴포넌트에서 사용할 수 있도록 해준다.

  • History API: 웹 애플리케이션의 브라우저 세션 기록을 조작할 수 있게 해주는 API이다. URL을 변경하고 브라우저의 뒤로 가기/앞으로 가기 버튼과 같은 탐색 기능을 제어할 수 있으며, 페이지를 새로 고침하지 않고도 URL을 변경할 수 있다.

3-3. 페이지 컴포넌트 만들기

이제 여러 페이지로 구성된 웹 애플리케이션을 만들기 위해 각 페이지에서 사용할 컴포넌트를 만들 차례이다. 사용자가 웹 사이트에 들어오게 됐을 때 가장 먼저 보여지게 될 Home 페이지 컴포넌트와 웹 사이트를 소개하는 About 페이지 컴포넌트를 만들어보자.

src 디렉터리에 pages 경로를 만든 후에 다음 파일들을 생성하였다.

이 컴포넌트들을 src/pages 에 넣은 이유는 단순히 편의성 때문이니 경로의 이름이 달라도 되고, src/ 에 바로 생성해도 문제없다.


3-4. Route 컴포넌트로 특정 경로에 원하는 컴포넌트 보여주기

주소창의 값에 따라 특정 컴포넌트를 보여주기 위해서는 Route 라는 컴포넌트를 통해 라우트 설정을 해주어야 한다.

Route 컴포넌트는 다음과 같이 사용한다.

<Route path = "주소규칙" element = {보여줄 컴포넌트 JSX} />

그리고 Route 컴포넌트는 Routes 컴포넌트 내부에서 사용되어야 한다.

App.js 에 Route 컴포넌트를 사용하여 라우트 설정을 해보자.

이후 실행해보면

이렇게 홈 컴포넌트가 나타난 것을 볼 수 있다.


3-5. Link 컴포넌트를 사용하여 다른 페이지로 이동하는 링크 보여주기

이번에는 Link 컴포넌트를 사용하여 다른 페이지로 이동하는 링크를 보여주는 방법을 알아보자.

원래 링크를 보여줄 때는 a태그를 사용하지만 리액트 라우터를 사용하는 프로젝트는 a태그를 사용하면 안된다. a태그를 클릭하여 페이지를 이동하면 페이지를 새로 불러오기 때문이다.

 

Link 컴포넌트도 a태그를 사용하긴 하지만, 페이지를 새로 불러오는 것을 막고 History API 를 통해 브라우저 주소의 경로만 바꾸는 기능이 내장되어 있다.

 

Link 컴포넌트는 다음과 같이 사용한다.

<Link to = "경로">링크 이름</Link>

 

Home 페이지에서 About 페이지로 이동할 수 있도록 Link 컴포넌트를 Home.js에서 사용해보자.


4. URL 파라미터와 쿼리스트링

페이지 주소를 정의할 때 유동적인 값을 사용해야 할 때도 있다.

URL 파라미터는 주소의 경로에 유동적인 값을 넣는 형태고, 쿼리 스트링은 주소의 뒷부분에 ? 문자열 이후에 key=value 로 값을 정의하며 & 로 구분을 하는 형태이다.

  • URL 파리미터 예시: /profile/rswoo
  • 쿼리스트링 예시: /articles?**page=1&keyword=react

URL 파라미터는 주로 ID 또는 이름을 사용하여 특정 데이터를 조회할 때 사용하고, 쿼리스트링은 키워드 검색, 페이지네이션, 정렬 방식 등 데이터 조회에 필요한 옵션을 전달할 때 사용한다.


4-1. URL 파라미터

URL 파라미터를 사용하는 방법을 알아보기 위해 새로운 페이지 컴포넌트인 Profile.js를 pages 경로에 다음과 같이 작성했다.

useParams 라는 Hook을 통해 URL 파라미터를 객체 형태로 조회할 수 있다. URL 파라미터의 이름은 라우트 설정을 할 때 Route 컴포넌트의 path props를 통해 설정한다.

 

이 코드에서는 data 객체에 예시 프로필 정보들을 key-value 형태로 담아두었다.

Profile 컴포넌트에서는 username URL 파라미터를 통하여 프로필을 조회한 뒤에 프로필이 존재하지 않으면 '존재하지 않는 프로필입니다.' 를, 존재한다면 프로필 정보를 보여주도록 작성했다.

 

이후 App.js에서 새로운 라우트를 다음과 같이 설정해준다.

URL 파라미터는 위와 같이 경로에 콜론(:)을 사용하여 설정한다. 만약 URL 파라미터가 여러개라면 /profiles/:username/:field 와 같은 형태로도 설정할 수 있다.

 

이제 Profile 페이지로 이동할 수 있도록 Home 컴포넌트를 수정해보자.

이제 Home 페이지에서 각 프로필로 이동할 수 있다.


4-2. 쿼리스트링

쿼리스트링을 사용할 때는 URL 파라미터와 달리 Route 컴포넌트를 사용할 때 별도로 설정해야되는 것은 없다.

API를 실습할 때 axios.get("url", { params })를 사용했는데 이 때 params객체를 axios에서 자동으로 쿼리스트링으로 변환해주었다.

 

우선 쿼리스트링을 화면에 띄어보기 위해 About 컴포넌트를 다음과 같이 수정한다.

여기서 사용한 useLocation 이라는 Hook은 현재 사용자가 보고있는 페이지의 정보를 지닌 location 객체를 반환한다. 이 객체에는 다음과 같은 값들이 있다.

  • pathname: 현재 주소의 경로 (쿼리스트링 제외)
  • search: 맨 앞의 ? 문자 포함한 쿼리스트링 값
  • hash: 주소의 # 문자열 뒤의 값 (주로 해시 라우터에서 사용)
  • state: 페이지로 이동할 때 임의로 넣을 수 있는 상태 값
  • key: location 객체의 고유 값, 초기에는 default 이며 페이지가 변경될 때마다 고유의 값이 생성됨.

주소창에 localhost:3000/about?test=123&username=rswoo 를 작성하면

위와 같은 값이 나타나는 것을 확인할 수 있다.

 

쿼리스트링 값이 ?test=123&username=rswoo 으로 표시가 되고 있는데 이 문자열에서 앞에 있는 ? 를 지우고, & 로 분리한 뒤 key 와 value 를 파싱하는 작업을 해야한다. 이 작업은 보통 npm에서 qs 또는 querystring 패키지를 설치해서 처리할 수 있다.

 

쿼리스트링을 따로 파싱까지 해야한다면 번거로울 수도 있는데, 리액트 라우터에서는 v6부터 useSearchParams 라는 Hook을 통해서 쿼리스트링을 쉽게 다룰 수 있게 됐다.

 

이 Hook을 사용하여 쿼리스트링을 파싱해보자.

useSearchParams 는 배열 타입의 값을 반환한다.

첫 번째 원소는 쿼리파라미터를 조회하거나 수정하는 메서드들이 담긴 객체를 반환한다. get 메서드를 통해 특정 쿼리파라미터를 조회할 수 있고, set 메서드를 통해 특정 쿼리파라미터를 업데이트 할 수 있다. 만약 조회 시에 쿼리파라미터가 존재하지 않는다면 null 로 조회된다.

두 번째 원소는 쿼리파라미터를 객체 형태로 업데이트할 수 있는 함수를 반환한다.

 

쿼리파라미터를 사용할 때 주의할 점은 쿼리파라미터를 조회할 때의 값은 무조건 문자열 타입 이라는 것이다.

boolean 값을 넣게 된다면 값을 비교할 때 꼭 'true'와 같이 따옴표로 감싸서 비교해야하고, 숫자를 다룰 때에는 parseInt를 사용하여 숫자 타입으로 변환해야한다.


5. 중첩된 라우트

이번에는 리액트 라우터에서 중첩된 라우트를 다룰 때 어떻게 해야 하는지에 대해 배울 것이다.

우선, 중첩된 라우트를 이해하기 위해 게시글 목록을 보여주는 페이지와, 게시글을 읽는 페이지를 만들어보자.

 

pages 디렉터리에 새 페이지 컴포넌트를 만든다.

이후, 해당 페이지들의 라우트를 App.js에서 설정하고

Home.js에서 게시글 목록 페이지로 가는 링크를 추가한다.

 

이때, 게시글을 열었을 때, 게시글의 하단에 목록을 보여주고 싶다면 어떨까?

 

기존 방식으로 구현한다면 새로운 컴포넌트를 만들어서 각 페이지 컴포넌트에서 사용해야됐을 것이다.

만약 중첩된 라우트를 사용한다면 좀 더 나은 방식으로 구현할 수 있다.

중첩된 라우트 형태로 라우트를 설정해보자.

 

App.js 를 다음과 같이 수정한다.

 

이후, Articles 컴포넌트에서 리액트 라우터에서 제공하는 Outlet 이라는 컴포넌트를 사용해주어야 한다.

이 컴포넌트는 Route 의 children 으로 들어가는 JSX 엘리먼트를 보여주는 역할을 한다. 

위 코드에서 Outlet 컴포넌트가 사용된 자리에 중첩된 라우트가 보여지게된다.

http://localhost:3000/articles http://localhost:3000/articles/1


5-1. 공통 레이아웃 컴포넌트

중첩된 라우트와 Outlet 은 페이지끼리 공통적으로 보여줘야 하는 레이아웃이 있을 때도 유용하게 사용할 수 있다.

 

만약 각 페이지의 상단에 헤더를 보여줘야 하는 상황을 가정했을 때, Header 컴포넌트를 따로 만들어 각 페이지 컴포넌트에서 재사용하지 않고, 중첩된 라우트와 Outlet 을 활용하여 구현할 수 있다.

 

중첩된 라우트를 사용하는 방식을 사용하면 컴포넌트를 한 번만 사용해도 된다는 장점이 있지만, 상황과 취향에 따라 원하는 방식으로 구현하면 된다.

 

중첩된 라우트를 통해 공통 레이아웃 컴포넌트를 사용해보자.

우선 Layout 컴포넌트를 src 디렉터리에 다음과 같이 작성한다.

헤더를 구현했기 때문에 Outlet 컴포넌트를 <main /> 안에 넣어주었다.

이후 App 컴포넌트를 다음과 같이 수정한다.

 

이제 Home 페이지에 들어가보면 아래와 헤더가 나타난다.

Home 말고도 About, Profiles 에서도 헤더가 나타닌다.


5-2. index props

Route 컴포넌트에는 index라는 props가 있다. 이 props 는 path="/" 와 동일한 의미를 가진다.

 

Home 컴포는트가 사용된 Route 컴포넌트를 다음과 같이 변경해보자.

여전히 / 경로로 들어갔을 때 Home 페이지가 나온다.

index props 는 상위 라우트의 경로와 일치하지만, 그 이후에 경로가 주어지지 않았을 때 보여지는 라우트를 설정할 때 사용한다.


6. 리액트 라우터 부가기능

리액트 라우터는 웹 애플리케이션에서 라이퉁에 관련딘 작업을 할 때 사용할 수 있는 유용한 API들을 제공한다.


6-1. useNavigate

useNavigate 는 Link 컴포넌트를 사용하지 않고 다른 페이지로 이동해야하는 상황에 사용하는 Hook이다.

 

Layout 컴포넌트를 다음과 같이 수정해보자.

헤더에 버튼 두 개가 나타나고, 버튼을 눌렀을 때 이전 페이지로 이동하거나, 게시글 목록 페이지로 이동된다.

 

navigate 함수를 사용할 때 파라미터가 숫자 타입이라면 양수일 때는 절댓값만큼 앞으로 가고, 음수일 때는 절댓값만큼 뒤로 간다.

navigate(-2) 을 하면 두 번 뒤로 가고, navigate(1) 을 하면 한 번 앞으로 가는 식이다.

 

다른 페이지로 이동할 때 replace 라는 옵션이 있는데, 이 옵션을 사용하면 페이지를 이동할 때 현재 페이지를 페이지 기록에 남기지 않는다.

Layout.js 의 goArticles 함수를 위와 같이 수정하면

Home 페이지 > About 페이지 > 헤더의 게시글 목록 버튼 클릭

이 순서대로 진행한 뒤, 뒤로가기 버튼을 누르면 About 페이지가 아닌 Home 페이지로 이동한다.


6-2. NavLink

NavLink 컴포넌트는 링크에서 사용하는 경로가 현재 라우트의 경로와 일치하는 경우 특정 스타일이나 CSS 클래스를 적용하는 컴포넌트이다.

 

이 컴포넌트를 사용해 style 또는 className 을 설정할 때 { isActive: boolean } 을 파라미터로 전달받는 함수 타입의 값을 전달한다.

<NavLink 
  style={({isActive}) => isActive ? activeStyle : undefined} 
/>

 

Articles 페이지 컴포넌트에서 이 컴포넌트를 사용하여 현재 보고있는 게시글을 표시해보자.

잘 작동하긴 하지만 반복되는 코드가 여러번 사용되고 있다.

이 때 NavLink 를 감싼 다른 컴포넌트를 만들어서 사용하면 좋다.


6-3. NotFound 페이지 만들기

NotFound 페이지란 사전에 정의되지 않은 경로에 사용자가 진입했을 때 보여주는 페이지이다. 즉, 페이지를 찾을 수 없을 때 나타난다.

 

우선 pages 디렉터리에 NotFound 페이지를 작성해준다.

이후 App 컴포넌트를 아래와 같이 수정한다.

여기서 * 는 wildcard 문자이다. 이는 아무 텍스트나 매칭한다는 뜻으로, 이 라우트 엘리먼트의 상단에 위치하는 라우트들을 모두 확인하고, 일치하는 라우트가 없다면 이 라우트가 화면에 나타나게 된다.

 

NotFound 에는 무조건 404가 따라오기에 찾아봤더니 HTTP 상태코드 404가 Not Found 를 의미한다고 한다.


6-4. Navigate 컴포넌트

Navigate 컴포넌트는 컴포넌트를 화면에 보여주는 순간 다른 페이지로 이동을 할 때 사용된다.

즉, 페이지를 리다이렉트할 때 사용한다. 예를 들어 로그인이 필요한 페이지에 로그인을 하지 않고 접근했을 때 로그인 페이지를 보여주도록 할 수 있다.

  • 리다이렉트(Redirect): 특정 요청을 받았을 때 현재 웹 페이지를 특정 URL로 이동시키는 프로세스

우선 pages 디렉터리에 페이지 컴포넌트 두 개를 작성한다.

위 코드에서는 isLoggedIn 이 false라는 고정값을 가지지만, 이 값이 로그인 상태에 따라 바뀐다고 가정해보자.

 

MyPage 컴포넌트를 보면 isLoggedIn 이 false 라면 Navigate 컴포넌트를 통해 /login 경로로 이동한다.

또한 여기서 사용된 replace props 는 useNavigate 에서 설명한 것과 동일한 역할을 한다.

 

MyPage 컴포넌트로 이동할 수 있도록 App 컴포넌트와 Home 컴포넌트를 수정해주면

My Page 를 클릭해도 로그인 페이지로 이동하는 것을 확인할 수 있다.

 

MyPage 컴포넌트의 isLoggedIn 을 true 바꿔주면 접근할 수 있게된다.

반응형