Lsiron

Custom hook, styling, SPA와 라우팅 본문

프론트엔드/React

Custom hook, styling, SPA와 라우팅

Lsiron 2024. 5. 30. 03:31

1. Custom hook

Custom hook은 React에서 상태 관리나 비즈니스 로직을 재사용하기 쉽게 만들어주는 기능이다. 일반적으로 함수의 형태로 작성되며, useState, useEffect 등의 React 훅을 사용하여 필요한 로직을 구현할 수 있다.

예를 들어, 사용자가 입력한 값을 로컬스토리지에 저장하고 싶을 때 custom hook을 사용할 수 있다. 아래는 간단한 예제 코드이다.

import { useState } from 'react';

const useCounter = () => {
  const [count, setCount] = useState(0);

  const increment = () => {
    setCount(count + 1);
  };

  return { count, increment };
};

export default useCounter;

 

=> 이 custom hook은 count와 increment 함수를 반환한다. 이제 이 custom hook을 사용하여 간단한 카운터 컴포넌트를 만들어보자.

import React from 'react';
import useCounter from './useCounter';

const Counter = () => {
  const { count, increment } = useCounter();

  return (
    <div>
      <h1>{count}</h1>
      <button onClick={increment}>증가</button>
    </div>
  );
};

export default Counter;

 

=> 이렇게 custom hook을 사용하면 Counter 컴포넌트에서 count 상태와 증가 함수를 간편하게 사용할 수 있다. 코드를 재사용하고 가독성을 높이는 데 custom hook이 얼마나 유용한지 보여준다.

 

쉽게 말해서 이름이 ”use“로 시작하고, 안에서 다른 Hook을 호출한다면 그 함수를 custom Hook이라고 부를 수 있다.

2. react 스타일링 (styled components)

리액트에서는 다양한 스타일링 방법을 사용할 수 있다. 주요한 리액트 스타일링 방법은 다음과 같다:

 

1. CSS 파일: 기존의 CSS 파일을 사용하여 스타일을 적용할 수 있다. 컴포넌트에 className을 추가하여 해당 CSS 스타일을 적용할 수 있다.

// Button.js

import React from 'react';
import './styles.css';

const Button = () => {
  return <button className="button">Click me</button>;
}

export default Button;

/* styles.css */

.button {
    background-color: blue;
    color: white;
    padding: 10px 20px;
  }

 

 

2. Inline styles: JSX 내부에 스타일 객체를 작성하여 인라인 스타일을 적용할 수 있다. 예를 들어, style 속성에 객체 형태로 스타일을 지정할 수 있다. (단, jsx파일이라면 {{buttonStyle}} 로 작성해야함. 외부 중괄호는 자바스크립트 적용, 내부 중괄호는 스타일 객체 적용)

// Button.js

import React from 'react';

const buttonStyle = {
  backgroundColor: 'blue',
  color: 'white',
  padding: '10px 20px',
};

const Button = () => {
  return <button style={buttonStyle}>Click me</button>;
}

export default Button;

 

 

3. CSS-in-JS: CSS-in-JS 라이브러리를 사용하여 JavaScript 코드 내부에서 스타일을 정의하고 적용할 수 있다. 대표적인 CSS-in-JS 라이브러리로는 styled-components, Emotion 등이 있다.

// Button.js

import React from 'react';
import styled from 'styled-components';

<button className='styledButton'>Click me</button>
 
export default Button;

// Button.css

.styledButton {
    background-color: blue;
    color: white;
    padding 10px 20px;
 }

 

=> 기존에 사용하던 위 사용법을 CSS-in-JS 방식으로 바꾸면 아래와 같다.

// Button.js

import React from 'react';
import styled from 'styled-components';

const StyledButton = styled.button=> template literal을 사용한다.
  background-color: blue;
  color: white;
  padding: 10px 20px;
`;

const Button = () => {
  return <StyledButton>Click me</StyledButton>;
}

export default Button;

 

=> template literal을 사용하여 CSS 파일이 없어도 CSS를 적용한 요소 자체를 변수로 선언하여 사용하는 모습을 볼 수 있다. 그렇다면 styled-components, Emotion 둘의 차이는 뭘까? 앞서 예시를 들었던 방법이 바로 styled-components를 사용한 방법이다. 그렇다면 Emotion에 대해 알아보자.

// Button.js

import React from 'react';
import { jsx, css } from '@emotion/react';

const buttonStyle = css`
  background-color: blue;
  color: white;
  padding: 10px 20px;
`;

const Button = () => {
  return <button css={buttonStyle}>Click me</button>;
}

export default Button;

 

=> 위 코드에서는 Emotion의 css 함수를 사용하여 버튼에 적용할 스타일을 정의한 후, css 속성을 통해 해당 스타일을 버튼에 적용합니다.

두 라이브러리 모두 강력하고 유연한 스타일링 솔루션을 제공하며, 각각의 특징과 장단점을 고려하여 프로젝트에 적합한 라이브러리를 선택할 수 있다.

 

 

4. CSS 프레임워크: 리액트 애플리케이션에 CSS 프레임워크를 사용하여 미리 정의된 스타일을 적용할 수 있다. 대표적으로 Bootstrap, Material-UI 등이 있다.

 

// App.js
import React from 'react';
import Button from '@material-ui/core/Button';

const App = () => {
  return <Button variant="contained" color="primary">Click me</Button>;
}

export default App;

 

 

현업에서 가장 많이 사용되는 스타일링 방법은 CSS-in-JS 라이브러리인 styled-components와 Emotion

이 두 라이브러리는 JavaScript 코드 내에서 스타일을 정의하고 관리하기 때문에 컴포넌트 기반으로 스타일을 관리할 수 있어 매우 편리하고 유지보수가 용이하다.

그렇다면 왜 기존에 CSS파일을 만들어서 쓰는 방법을 안 하는 것 일까?? 바로 이 방식의 단점 때문이다. 기존의 CSS 파일을 사용하는 방법의 단점은 다음과 같다:

 

1. 클래스 이름 충돌: 전역 스코프로 작동하는 CSS 파일은 클래스 이름이 충돌할 수 있다. 특히 대규모 애플리케이션에서는 이를 방지하기 위해 클래스 네이밍 규칙을 엄격하게 지켜야 한다.

 

2. 스타일 관리의 어려움: CSS 파일은 컴포넌트와 스타일이 분리되어 있기 때문에 스타일 관리가 어려울 수 있다. 특히 동적인 스타일링이 필요한 경우에는 유연하게 대처하기 어렵다.

 

3. 코드 가독성 저하: CSS 파일을 사용하면 HTML과 CSS가 분리되어 있기 때문에 코드 읽기가 어려울 수 있다. 특히 스타일이 어떤 컴포넌트에 적용되는지 바로 파악하기 어려울 수 있다.

 

하긴 어느세월에 해당 요소에 적용된 style을 한 css파일에 들어가서 찾을 수 있단 말인가.. 이러한 단점을 극복하기 위해 CSS-in-JS 라이브러리를 사용하여 스타일을 관리하는 추세가 현업에서 많이 보고 있다. 이를 통해 컴포넌트 기반으로 스타일을 관리하고 코드의 가독성을 높일 수 있다.

 

 

3. SPA와 라우팅 

SPA?

SPA(Single Page Application)는 모든 웹 애플리케이션 리소스(HTML, CSS, JavaScript)를 한 번에 불러오고, 이후에는 페이지 갱신을 위해 서버로부터 새로운 페이지 전체를 다시 불러오지 않고 필요한 데이터만을 비동기적으로 불러오는 형태의 웹 애플리케이션이다. 즉, 게시판에 1,2,3,4,5쪽 까지 있다면 현재 1쪽에서 2쪽으로 넘어갈때 페이지가 다시 로드 되지않고 게시판 목록만 바뀐다는 것. (그때그때 게시판 내부에서 이동할때마다 페이지를 불러오는 것이 아니라, 홈페이지에 들어왔을때 미리 게시판 정보를 처음부터 다 불러오고 필요할 때 마다 가져다가 쓰는 방식이다. )

과거에는 React Router나 SPA와 같은 기술이 없었을 때, 웹 애플리케이션은 여러 페이지로 구성되어 각 페이지를 이동할 때마다 전체 페이지를 새로고침하여 콘텐츠를 로드했다. 이를테면 사용자가 다른 페이지로 이동할 때마다 서버로부터 전체 페이지의 HTML, CSS, JavaScript 등의 리소스를 다시 받아와야 했기 때문에 페이지 간 전환 속도가 느렸고 사용자 경험이 떨어졌다. 즉, 내가 게시판 2페이지의 글을 보고싶은데 이 2페이지를 불러오기위해 게시판을 포함한 페이지의 모든 요소를 다 다시 불러왔다는 것이다.  허나, 이러한 꿀방식에도 장점과 단점은 명확하게 존재한다.

 

장점

1. 로딩 속도: SPA는 초기에 필요한 리소스만 로드하고, 페이지 간 전환이 클라이언트 측에서 이루어지기 때문에 더 빠른 로딩 속도를 제공한다.

 

2.부드러운 사용자 경험: 페이지 간 전환 시 전체 페이지를 새로고침하지 않아도 되므로 사용자가 부드럽고 빠르게 콘텐츠를 탐색할 수 있다.

 

3. 서버 요청 감소: SPA는 서버에 필요한 데이터만 요청하고, 클라이언트 측에서 렌더링하므로 서버 요청을 줄일 수 있다.

 

4.상태 관리 용이성: React Router와 SPA를 사용하면 각 페이지 간의 상태를 유지하거나 전달하기 쉽다.

 

단점

1. 초기 로딩 시간: SPA는 초기에 필요한 리소스를 모두 다운로드해야 하므로 초기 로딩 시간이 길어질 수 있다.

 

2. 검색 엔진 최적화(SEO) 어려움: SPA는 클라이언트 측에서 콘텐츠를 렌더링하므로 검색 엔진이 콘텐츠를 크롤링하기 어려울 수 있다. ( 크롤링(crawling) 은 웹 페이지를 그대로 가져와서 거기서 데이터를 추출해 내는 행위다.)

 

3. 메모리 관리: SPA는 클라이언트 측에서 상태를 유지하므로 메모리 사용량이 증가할 수 있으며, 메모리 누수가 발생할 수 있다.

 

4. 이 외에도 단점은 가지각색으로 존재한다. 예를 들어, 게시판 2페이지를 즐겨찾기에 등록할 수 없고, 뒤로가기를 눌렀을때 아예 게시판 이전 페이지를 간다던지 혹은 새로고침을 했을때 게시판 1페이지로 넘어간다던지. 의외로 많다.  

 

 

라우팅?

위 4번의 단점을 해결하기 나온것이 바로 Routing. 사용자가 웹 애플리케이션에서 새로운 URL을 요청하거나 링크를 클릭할 때, 해당 URL에 따라 적절한 컨텐츠를 사용자에게 보여주는 것이 라우팅이다. 라우팅을 통해 사용자는 여러 페이지 간을 이동하거나 특정 페이지로 직접 이동할 수 있다.  리액트에선 주로 react-router 라이브러리를 활용하여 라우팅을 쉽게 할 수 있다.

 

리액트에서 라우팅을 사용하는 방법?

리액트에서 라우팅을 사용하기 위해서는 React Router 라이브러리를 설치하고 적절히 설정해야 한다. 먼저, 프로젝트 디렉토리에서 다음 명령어를 사용하여 React Router를 설치해준다 .

 npm install react-router-dom

 

라이브러리 설치 후 package.json에 들어가있는지 확인 해 준다.

확인 후, 라우팅을 적용하고 싶은 컴포넌트에서 React Router의 컴포넌트들을 import 해야 한다. 예를 들어, App.js에서 라우팅을 설정하고 싶다면 다음과 같이 컴포넌트를 import 한다. 아래는 가장 많이 사용되는 모듈 4가지 이다.

 import { BrowserRouter, Routes, Route, Link } from 'react-router-dom';

 

예시코드를 보면서 이 코드를 분석하며, 각각 코드의 역할을 알아보자.

import React from 'react';
import { BrowserRouterRoutesRoute, Link } from 'react-router-dom';
import Header from './Header';
import Footer from './Footer';

const Home = () => (
  <div>
    <h1>홈 페이지</h1>
    <Link to="/Product">제품 소개 페이지로 이동</Link>
  </div>
);

const Product = () => (
  <div>
    <h1>제품 소개 페이지</h1>
    <Link to="/">홈 페이지로 이동</Link>
  </div>
);

const NotFound = () => (
  <div>
    <h1>페이지를 찾을 수 없습니다.</h1>
  </div>
);

function App() {
  return (
    <BrowserRouter>
      <Routes>
        <Route path="/" element={<Home />/>
        <Route path="/product" element={<Product />/>
        <Route path="*" element={<NotFound />/>
      </Routes>
    </ BrowserRouter>
  );
}

export default App;

 

1. 먼저 앱 전체를 BrowserRouter로 감싼다.

=> BrowserRouter는 앱 전체를 감싸는 역할을 하며, URL의 변화에 따라 애플리케이션의 상태를 업데이트하고 해당하는 컴포넌트를 보여주는 역할을 한다. 이를 통해 사용자가 원하는 페이지로 이동할 때마다 새로고침 없이 페이지를 렌더링할 수 있다.

또한, BrowserRouter는 HTML5 history API를 사용하여 브라우저 히스토리를 관리하고, 뒤로 가기, 앞으로 가기 같은 브라우저의 기능을 React 애플리케이션에서도 사용할 수 있도록 해준다.

 

? HTML5 history API 는 갑자기 뭐지? 

 

HTML5 history API는 웹 브라우저의 세션 히스토리를 조작하고 관리하는 JavaScript API이다. 이 API를 사용하면 브라우저의 URL을 변경하거나 새로운 세션 히스토리 엔트리를 추가할 수 있다. 또한, 뒤로 가기, 앞으로 가기 같은 브라우저의 기능을 제어하거나 사용자 정의한 세션 히스토리를 관리할 수 있다.  

 

즉, BrowserRouter의 기능은 두 가지. 

1) 기본적으로 URL 변화에 따라 해당하는 컴포넌트를 가져와준다. 어떻게? 기본 성질이다.

(위 코드에선 /about 으로 가면 {about} 컴포넌트를 가져와줌) 

 

2) 새로고침, 뒤로가기, 앞으로가기 기능이 가능하게 한다. 어떻게? HTML5 history API라는 도구를 써서.(웹 사용자의 과거활동을 관장함. 이 정보를 기반으로 새로고침 등 이런 기능이 가능하도록 함.) 

 

그러니까 나 없으면 너네 시작도 못 하는데 일단 시작하면 많이 도와줄께 이런 느낌.

일단 라우팅 할때 가장 먼저 붙여줘야하는 녀석이다.

 

간혹 import { BrowserRouter as Router } from 'react-router-dom'; 이렇게 import 한 뒤, <BrowserRouter> 

신 <Router> 로 감싸주는 경우가 있다.

Router는 BrowserRouter, HashRouter, MemoryRouter 등 다양한 타입이 있는데, BrowserRouter는 Router 타입 중 하나이다. 즉, 근본은 Router이며,

import { BrowserRouter as Router } from 'react-router-dom'; 로 import해서 <Router>  로 감싸든,

import { BrowserRouter from 'react-router-dom'; 로 import해서 <BrowserRouter> 로 감싸든, 상관없다.

허나 일반적으로는 BrowserRouter를 많이 쓴다. 단, 저 BrowserRouter, HashRouter, MemoryRouter 타입들 마다 각각의 역할과 동작 방식이 조금씩 다를 수 있다. 잘 알아보고 사용하도록 하자.

 

2. Routes로 header와 footer를 제외한 모두를 감싸준다.

=> Routes는 라우트 정의를 관리하는 컴포넌트로, Routes 컴포넌트 안에 여러 Route 컴포넌트를 포함하여 경로(path)와 컴포넌트 간의 매칭을 설정한다. 사용자가 URL을 변경할 때 Routes는 해당하는 Route 컴포넌트를 렌더링하여 화면에 보여준다.

 

그런데 Header와 Footer는 왜 제외하지?

Routes 문은 주로 페이지의 내용을 변경할 때 사용되며, 일반적으로 페이지의 콘텐츠 부분만을 교체하게 된다.

Header와 Footer는 웹 페이지의 상단과 하단에 위치하는 고정된 요소로, 일반적으로 페이지 내용이 변경되더라도 일관된 디자인을 유지하기 위해 변경되지 않는 부분이다.

 

다시 말해서,  Header와 Footer는 모든 페이지에 다 나와야하기 때문에 그 안 쪽을 Routes로 감싸준다.

 

즉, 게시판 2쪽보는데 게시판 내용만 바뀌면 되고 Header와 Footer는 바뀔 필요가 없기 때문이라는 것. 

 

3. Routes 내부에 Route를 사용하여, 경로를 정해주고, 그 경로에 맞는 Component를 입력해준다.

=> Route는 개별 경로와 컴포넌트 간의 매칭을 설정하는 컴포넌트로, path 속성에 경로를 지정하고 component 속성에 해당 경로에 매칭될 컴포넌트를 지정한다. 사용자가 해당 경로로 이동하면 Route 컴포넌트는 지정된 컴포넌트를 렌더링하여 화면에 보여준다. 주로 Routes 컴포넌트 안에서 사용되어 각 경로에 따라 다른 컴포넌트를 렌더링하는 역할을 한다.

 

 

4. React Routing 에선 <a href> 대신 link to 를 쓴다. (Declarative 형식)

=> 먼저 React Router에서 Link 컴포넌트를 사용하여 페이지 간 이동을 할 수 있는데, Link 컴포넌트는 사용자가 클릭할 때 새로고침 없이 페이지를 변경할 수 있게 해준다.

즉, 여기선 <a href>대신 link to를 쓴다는 것.

import { Link } from 'react-router-dom';

const Home = () => (
  <div>
    <h1>홈 페이지</h1>
    <Link to="/product">제품 소개 페이지로 이동</Link>
  </div>
);

 

먼저 import { Link } from 'react-router-dom'; 를 통해 Link를 import 해 주어야 한다.

위 코드에서 Link 컴포넌트를 사용하여 “제품 소개 페이지로 이동”이라는 텍스트를 클릭하면 “/about” 경로로 이동하는 링크가 생성된다.

 

5. NotFound

=> path=”*”는 모든 경로를 의미한다. 즉, 사용자가 입력한 모든 경로에 대해 NotFound 컴포넌트를 렌더링하게 된다. 이렇게 설정함으로써, 지정한 경로를 제외한 존재하지 않는 경로로 접근했을 때 NotFound 페이지를 보여줄 수 있다.

("/" 와 "/product" 를 제외한 경로는 NotFound 처리가 된다.)

 

6. URL 파라미터

=> React에서 URL 파라미터는 주소창에 있는 경로의 일부를 나타내는 것을 말한다. 예를 들어, “/product/:id”와 같은 형식으로 URL을 정의하면 “:id” 부분이 URL 파라미터가 된다.

이를 통해 동적인 데이터를 불러오거나 특정 페이지로 이동할 때 유용하게 활용할 수 있다.

import React from 'react';
import { BrowserRouter, Routes, Route, Link, useParams } from 'react-router-dom';
import Header from './Header';
import Footer from './Footer';

const Home = () => (
  <div>
    <h1>홈 페이지</h1>
    <Link to="/product/123">제품 소개 페이지로 이동</Link>
  </div>
);

const Product = () => {
  const { id } = useParams();

  return (
    <div>
      <h1>제품 소개 페이지</h1>
      <p>제품 ID: {id}</p>
      <Link to="/">홈 페이지로 이동</Link>
    </div>
  );
};

const NotFound = () => (
  <div>
    <h1>페이지를 찾을 수 없습니다.</h1>
  </div>
);

function App() {
  return (
    <BrowserRouter>
      <Routes>
        <Route path="/" element={<Home />} />
        <Route path="/product/:id" element={<Product />} />
        <Route path="*" element={<NotFound />} />
      </Routes>
    </ BrowserRouter>
  );
}

export default App;

 

먼저 import { useParams } from 'react-router-dom'; 를 통해 Link를 import 해 주어야 한다.

처음 예시 코드에서는 product에 URL 파라미터를 적용하는 대신, 단순히 “/Product” 경로로 이동하는 Link를 넣었다.

URL 파라미터를 적용하려면 Route의 path 속성을 “/product/:id”와 같이 설정해야 한다. 그리고 Product 컴포넌트에서 useParams 훅을 사용하여 id 값을 가져와서 사용해야 한다.

 

위와 같이 useParams를 넣고 코드를 짜면, 이제 “/product/123”과 같은 경로로 이동했을때 Product 컴포넌트에서 해당 id 값을 가져와서 화면에 출력할 수 있다.

 

7. 쿼리 스트링(★)

=> 현업에서 쿼리스트링으로 보내주라는 요청을 받을 때가 있다. 그럼 쿼리스트링으로 보내기 전에 활용 방법에 대해 알아야 한다.

쿼리스트링은 url의 한 부분으로써 특정 매개변수와 값을 전달하는데 사용된다. 즉, 쿼리스트링은 URL에 추가적인 정보를 전달하기 위해 사용되는 문자열이다.

 

즉, 제품 사이트에 수많은 상품이 있을 때 가격높은 순 등 원하는 순서대로 정렬되고 특정된 형태의 정보를 구체적으로 요청할 때 활용할 수 있다.

 

일반적으로 물음표(?)로 시작하며, key=value 형식으로 여러 개의 쌍을 & 기호로 구분하여 나열한다.

예를 들어, "https://lsiron.tistory.com/newpost?id=20&id=40"  라는 URL에서 쿼리스트링은 id=20&id=40 부분이다. 여기서 id는 key이고 20은 value이며, 쌍으로 id는 key이고 40인 value가 있다.

 

쿼리 스트링의 값을 가져올 수 있는 hook이 존재 하는데 바로, useLocation과 useSearchParams이다.

 

먼저 useLocation은 현재의 location 객체를 반환한다. 

 

location 객체는 현재 URL에 포함된 여러 가지 정보를 가지고 있고, 각각의 정보를 여러 프로퍼티 pathname, search, hash 등 으로 표현 하고 있다.  각각의 객체를 예시를 통해 알아보자.

 

1. pathname : 현재 URL의 경로명을 나타내는 프로퍼티이다. 이 프로퍼티는 현재 애플리케이션의 경로를 나타내기 때문에, 어떤 페이지에 접근했는지를 확인할 때 사용된다. 예를 들어, 특정 경로에 따라 다른 컴포넌트를 렌더링하거나 특정 기능을 수행할 때 pathname을 사용할 수 있다.

 

다음의 URL이 있다. https://lsiron.tistory.com/newpost  URL의 도메인 다음의 /를 식별자로써 /부터의 문자열이 pathname으로 들어간다. 여기선 "/newpost" 가 된다. 

여기서 주의해서 볼 부분은 pathname이 /로부터 끝까지가 아니라 도중에 ?라는 식별자를 만날 때까지 이라는 것.

 

2. search : 현재 URL의 쿼리 스트링을 나타내는 프로퍼티이다. 쿼리 스트링은 URL에 추가적인 정보를 담고 있는 부분으로, 검색 결과 필터링이나 페이지네이션 등에 활용된다. 쿼리 스트링을 파싱하여 필요한 정보를 추출하거나 필터링 기능을 구현할 때 search 프로퍼티를 사용할 수 있다.

 

url 주소를 변경해보자. https://lsiron.tistory.com/newpost?id=20 URL에서 ?가 식별자로써 ?부터 나오는 문자열 전부이다. 여기선 '?id=20' 가 해당된다.  => 실상 이것만 잘 알고 있으면 된다. 가장 중요!

 

 

3. hash : 현재 URL의 해시 부분을 나타내는 프로퍼티이다. 해시는 웹 페이지 내에서 특정 위치를 가리킬 때 사용되며, 주로 페이지 내 이동이나 앵커 링크 등에 활용된다. 특정 섹션으로 스크롤하거나 북마크 기능을 구현할 때 hash 프로퍼티를 사용할 수 있다.

 

url 주소를 변경해보자. https://lsiron.tistory.com/newpost#id=20 URL에서 #가 식별자로써 #부터 나오는 문자열 전부이다. 여기선 ' #id=20' 가 해당된다.

여기서도 주의해서 볼 부분은 pathname이 /로부터 끝까지가 아니라 도중에 #라는 식별자를 만날 때까지 이라는 것.

 

import { useLocation } from 'react-router-dom';
 
//URL : https://lsiron.tistory.com/newpost?id=20
 
const NewPost = () => {
  const location = useLocation();

  return (
    <div>
      <p>쿼리스트링:{location.search}</p>
    </div>
  );
};

export default NewPost

 

=> 위 코드는 useLocation 활용예시 이며,  location의 객체인 search를 통해 쿼리스트링을 추출하고자 한다. {location.search} 는 ?id=20 을 반환함을 알 수 있다.

 

허나, useLocation을 통해서 쿼리스트링의 값을 활용하고자 하는데 불편함이 있다. 전체 쿼리스트링을 하나의 문자열 형태 ?id=20"  로 표현하기 때문에 이 중에서 원하는 값만 가져오려면 문자열을 자바스크립트를 통해 파싱하는 과정을 거쳐야한다.

 

예를 들어, 쿼리스트링에서 id의 값을 얻고자한다면, ?를 문자열에서 제거하고, id문자열을 찾아내고 =뒤에 위치한 값을 최종적으로 꺼내오는 과정을 거쳐야한다는 것이다. 하지만 이런 복잡한 과정을 거치지 않고 원하는 쿼리스트링 값만 얻어낼 수 있는 useSearchParams라는 hook이 존재한다.

 

useSearchParams를 통해 쿼리 스트링에서 원하는 값만 추출해 낼 수 있고, useSearchParams hook을 호출하면 useState와 비슷하게 배열의 형태로 searchParams와 setSearchParams 함수를 리턴해준다.

const [searchParams, setSearchParams] = useSearchParams();

 

searchParams : URLSearchParams 객체, 쿼리스트링을 다루기 위한 여러 매서드 제공한다.(★)

setSearchParams  : 인자에 객체 또는 문자열을 넣어주면 URL의 쿼리스트링을 변경하는 기능을 제공한다.

searchParams는 URLSearchParams 객체이며 URLSearchParams 객체는 쿼리 스트링을 다루기 위한 여러 편리한 메서드를 제공한다.

 

searchParams의 자주 사용하는 메서드(★)

 

example) ?id=20&id=40

 

값을 읽어오는 메서드

1) searchParams.get(key)

=> 특정한 key의 value를 가져오는 메서드이다.

searchParams.get("id") => "20"

 

2) searchParams.getAll(key)

=> 특정한 key에 해당하는 모든 value를 가져오는 메서드이다.

searchParams.getAll("id") => ["20","40"]

 

3) searchParams.toString()

=> 쿼리 스트링을 string 형태로 리턴한다.  

searchParams.toString("id") => "?id=20&id=40"

 

값을 변경하는 메서드

1) searchParams.set(key, value)

=> 인자로 전달한 key값을 value로 설정하는 메서드이다.

searchParams.set("id", "30")      searchParams.toString() => "?id=30"

 

2) searchParams.append(key, value)

=> 기존 값을 변경하거나 삭제하지 않고 추가하는 방식으로 동작하는 메서드이다.

searchParams.append("id", "60")     》   searchParams.toString() => "?id=20&id=40&id=60"

import React from 'react';
import { useSearchParams } from 'react-router-dom';
 
const SearchResults = () => {
  const searchParams = useSearchParams();

  return (
    <div>
      <p>id: {searchParams.get('id')}</p>
    </div>
  );
}

export default SearchResults;

 

=> 위 코드는 useSearchParams 활용예시 이며,  {searchParams.get('id')} 는 20 을 반환함을 알 수 있다. 위에서 본 값을 읽어오는 메서드를 통해 쿼리스트링 값을 읽어왔다.

 

자 이제 useSearchParams 를 통해 쿼리스트링을 추출하는 방법을 알았으니 활용을 해보자.

import * as React from "react";
import { useSearchParams } from "react-router-dom";

function ProductList() {
  let [searchParams, setSearchParams] = useSearchParams();
  const category = searchParams.get("category");
  const sortBy = searchParams.get("sort");

  // 필터링 및 정렬된 상품 목록을 가져오는 로직 작성

  function handleCategoryChange(event) {
    setSearchParams({ category: event.target.value });
  }

  function handleSortChange(event) {
    setSearchParams({ sort: event.target.value });
  }

  return (
    <div>
      <h1>Product List</h1>
      <div>
        <label>
          Category:
          <select value={category} onChange={handleCategoryChange}>
            <option value="fruits">Fruits</option>
            <option value="vegetables">Vegetables</option>
          </select>
        </label>
      </div>
      <div>
        <label>
          Sort By:
          <select value={sortBy} onChange={handleSortChange}>
            <option value="price">Price</option>
            <option value="name">Name</option>
          </select>
        </label>
      </div>
      {/* 필터링된 및 정렬된 상품 목록을 렌더링하는 로직 */}
    </div>
  );
}

 

=> 위 코드는 React 함수 컴포넌트인 ProductList를 정의하고 있다. 이 컴포넌트는 react-router-dom 라이브러리의 useSearchParams 훅을 사용하여 URL의 쿼리스트링을 가져오고, 해당 쿼리스트링에서 “category”와 “sort” 파라미터 값을 추출하여 변수에 저장한다.

 

ProductList 컴포넌트는 상품 목록을 필터링하고 정렬하기 위한 UI를 제공한다. 사용자가 카테고리나 정렬 방식을 변경하면 해당 변경 내용을 URL의 쿼리스트링에 반영하여 페이지를 다시 렌더링한다. 이를 통해 사용자가 선택한 카테고리와 정렬 방식을 유지하면서 페이지를 이동할 수 있다.

 

handleCategoryChange 함수는 카테고리를 변경할 때 호출되며, 선택한 카테고리 값을 URL의 쿼리스트링에 반영한다. handleSortChange 함수는 정렬 방식을 변경할 때 호출되며, 선택한 정렬 방식을 URL의 쿼리스트링에 반영한다.

 

8. useNavigate

=> useNavigate는 React Router v6에서 제공하는 훅으로(v5에선 useHistory 였음), 페이지 이동을 처리하는데 사용된다. 예를 들어, 특정 버튼 클릭 시 다른 페이지로 이동하거나 특정 이벤트 발생 시 페이지를 변경할 때 useNavigate를 활용할 수 있다.

 

아래는 useNavigate를 사용하여 버튼 클릭 시 다른 페이지로 이동하는 예시 코드이다.

import React from 'react';
import { useNavigate } from 'react-router-dom';

const Home = () => {
  const navigate = useNavigate();

  const handleClick = () => {
    // '/about' 페이지로 이동
    navigate('/about');
  }

  return (
    <div>
      <h1>Home Page</h1>
      <button onClick={handleClick}>Go to About Page</button>
    </div>
  );
}

export default Home;

 

=> 위 코드에서는 useNavigate 훅을 사용하여 버튼 클릭 시 ‘/about’ 페이지로 이동하는 예시를 보여주었다. 버튼을 클릭하면 navigate 함수를 통해 해당 경로로 페이지가 이동된다. 페이지 이동을 처리할 때 useNavigate를 활용하여 간편하게 페이지 간 전환을 구현할 수 있다.

 

 

 

Tips

1. 모듈 사용법 : https://inpa.tistory.com/entry/JS-%F0%9F%93%9A-%EB%AA%A8%EB%93%88-%EC%82%AC%EC%9A%A9%ED%95%98%EA%B8%B0-import-export-%EC%A0%95%EB%A6%AC#%EB%8B%A4%EC%8B%9C_%EB%82%B4%EB%B3%B4%EB%82%B4%EA%B8%B0_/_%EC%A1%B0%ED%95%A9

 

[JS] 📚 모듈 사용하기 import / export 완벽 💯 정리

자바스크립트 모듈 개발하는 애플리케이션의 크기가 커지면 언젠간 파일을 여러 개로 분리해야 하는 시점이 옵니다. 이때 분리된 파일 각각을 '모듈(module)'이라고 부르는데, 모듈은 대개 클래스

inpa.tistory.com

 

 

 

2. pagenation (신입대상 과제로 많이 나옴)

React에서 pagination은 사용자가 데이터를 여러 페이지로 분할하여 볼 수 있도록 하는 기능을 말한다. 이를 통해 사용자는 페이지 단위로 데이터를 쉽게 살펴볼 수 있고, 페이지 이동을 통해 다양한 정보에 접근할 수 있다.

Pagination을 구현하는 방법 중 하나는 React의 state를 사용하여 현재 페이지 번호를 추적하고, 해당 페이지에 맞는 데이터를 렌더링하는 것이다. 아래는 간단한 pagination을 구현하는 예시 코드이다.

아래 코드는 React에서 pagination을 구현하는 예시로, useTodo.js 파일과 TodoList.jsx 파일로 구성되어 있다.

// useTodo.js

 
import { useState, useEffect } from 'react';
import axios from 'axios';



export const useTodo = () => {
    const [page, setPage] = useState(1);
    const [todos, setTodos] = useState([]);

    useEffect(() => {
        getTodos();
    }, [page]);

    const getTodos = () => {
        axios.get('https://jsonplaceholder.typicode.com/todos').then((response) => {
            setTodos(response.data.slice((page -1) * 10, page * 10)); //10개를 뽑는다
     });
    };

    const decreasePage = () => {
        if (page -1 > 0) {
            setPage(page - 1);
        }
    };

    const increasePage = () => {
        setPage(page + 1);
    };

    return {
        page,
        todos,
        setPage,
        onDecrease: decreasePage,
        onIncrease: increasePage,
    };
};

 

=> useTodo.js 파일은 custom hook인 useTodo를 정의하고 있다. 이 custom hook은 현재 페이지를 추적하고 해당 페이지에 맞는 할일 목록을 가져오는 기능을 제공한다. 초기 페이지는 1로 설정되어 있고, 페이지 이동을 위한 decreasePage와 increasePage 함수도 포함되어 있다. getTodos 함수에서는 axios를 사용하여 외부 API에서 할일 목록을 가져와 현재 페이지에 맞는 10개의 할일만 추출하여 설정한다.

 

// TodoList.jsx

 
import { useTodo} from '../hooks'

const TodoList = () => {
 const { page, todos, onIncrease, onDecrease } = useTodo();

    const handleClickPrev = () => {
        onDecrease();
    };

    const handleClickNext = () => {
        onIncrease();
    };

 return (
    <div>
        <div>
            <button onClick={handleClickPrev}>이전 페이지</button>
            <span>페이지 {page}</span>
            <button onClick={handleClickNext}>다음 페이지</button>
        </div>
    <ul>
        {todos.map(({title, id}) => {
            return <li key={id}>{title}</li>;
        })}
    </ul>
    </div>
 );
};

export default TodoList;

 

=> TodoList.jsx 파일은 TodoList 컴포넌트를 정의하고 있다. 이 컴포넌트에서는 useTodo custom hook을 사용하여 현재 페이지, 할일 목록, 페이지 이동을 위한 함수들을 가져와 렌더링한다. handleClickPrev와 handleClickNext 함수는 각각 이전 페이지로 이동하고 다음 페이지로 이동하는 버튼 클릭 시 실행된다.

 

TodoList 컴포넌트는 이전 페이지, 현재 페이지 번호, 다음 페이지 버튼을 렌더링하고 각 페이지에 해당하는 할일 목록을 출력한다.

 

3. cors(면접에 무조건 나옴)

 

1) cors가 무엇인가요? : Cross-Origin Resource Sharing의 약자로, 웹 애플리케이션에서 발생하는 보안 문제 중 하나이다.  웹 브라우저는 보안 상의 이유로 한 도메인에서 실행 중인 웹 페이지가 다른 도메인에 있는 리소스에 접근하는 것을 제한한다. 이를 Same-Origin Policy라고 한다. 이 오리진이 달라도 공유를 할 수 있는것이 바로 cors이다. 그런데 오리진이 같은경우에만 자원을 공유할 수 있도록 하는 same-origin도 있다.

 

2) cors 해결방법 두가지? => .  1. 기본적으로 서버의 허용이 필요하다.Access-Control-Allow-Origin 헤더에 허용할 출처를 기재해서 클라이언트에 응답하면 된다. 즉, 백엔드 개발자가 고쳐야될 부분이다. 2. 서버가 열어주기 힘든경우, 프록시사이트 이용하기 - 모든 출처를 허용한 서버 대리점을 통해 요청을 하면 된다. 

 

'프론트엔드 > React' 카테고리의 다른 글

axios(get, post, put, delete)  (2) 2024.06.02
상태관리(Context API)  (2) 2024.06.01
event처리, hooks  (0) 2024.05.24
JSX, Components, Props/State  (0) 2024.05.22
리액트 시작하기.  (0) 2024.05.19