[리액트를 다루는 기술] 13장. 리액트 라우터로 SPA 개발하기

Speedwell🍀·2022년 1월 6일
0

출처: <리액트를 다루는 기술> 책

1. SPA란?


MPA

  • 사용자가 다른 페이지로 이동할 때마다 새로운 html을 받아 옴
  • 페이지를 로딩할 때마다 서버에서 리소스를 전달받아 해석한 뒤 화면에 보여줌
    ➡ 사용자에게 보이는 화면은 서버 측에서 준비 (사전에 html 파일 생성 후 제공, 데이터에 따라 유동적인 html을 생성해 주는 템플릿 엔진 사용 ...)

👎 MPA 단점

  • 성능 문제
    • 웹에서 제공되는 정보량이 너무 많기 때문에 새로운 화면을 보여 줘야 할 때마다 서버측에서 모든 뷰를 준비한다면 성능상의 문제가 발생할 수 있음
    • ex) 트래픽이 너무 많이 나오거나, 서버에 높은 부하가 쉽게 걸릴 수 있음
  • 사용자와의 인터랙션이 자주 발생하는 모던 웹 애플리케이션에서는 적합하지 않을 수 있음
    • 애플리케이션 내에서 화면 전환이 일어날 때마다 html을 계속 서버에 새로 요청하면 사용자의 인터페이스에서 사용하고 있던 상태를 유지하는 것도 번거롭고, 바뀌지 않는 부분까지 새로 불러와서 보여 줘야 하기 때문에 불필요한 로딩 -> 비효율적

SPA

  • 리액트 같은 라이브러리나 프레임워크를 사용하여 사용자의 브라우저가 담당하도록 하고, 우선 애플리케이션을 브라우저에 불러와서 실행시킨 후에 사용자와의 인터랙션이 발생하면 필요한 부분만 자바스크립트를 사용하여 업데이트

  • 만약 새로운 데이터가 필요하면 서버 API를 호출하여 필요한 데이터만 새로 불러와 애플리케이션에서 사용 가능

  • 서버에서 사용자에게 제공하는 페이지는 한 종류이지만, 해당 페이지에서 로딩된 자바스크립트와 현재 사용자 브라우저의 주소 상태에 따라 다양한 화면을 보여 줄 수 있음

  • 라우팅: 다른 주소에 다른 화면을 보여 주는 것

    • 리액트 라이브러리 자체에 이 기능이 내장되어 있지는 않음 ➡️ 브라우저의 API를 직접 사용하여 이를 관리하거나, 라이브러리를 사용하여 이 작업을 더욱 쉽게 구현할 수 있음

      • 리액트 라우팅 라이브러리는 리액트 라우터(react-router), 리치 라우터(reach-router), Next.js 등
        • react-router: 클라이언트 사이드에서 이루어지는 라우팅을 아주 간단하게 구현할 수 있도록 해줌. 서버 사이드 렌더링 할 때도 라우팅을 도와주는 컴포넌트들을 제공해줌.

👎 SPA 단점

  • 앱의 규모가 커지면 JS 파일이 너무 커짐

    • 이유: 페이지 로딩 시 사용자가 실제로 방문하지 않을 수도 있는 페이지의 스크립트도 불러오기 때문
    • 코드 스플리팅(code splitting)을 사용하면 라우트별로 파일들을 나눠서 트래픽과 로딩 속도 개선 가능
  • JS를 실행하지 않는 일반 크롤러에서는 페이지의 정보를 제대로 수집해 가지 못할 수 있음

  • JS가 실행될 때까지 페이지가 비어 있기 때문에 JS 파일이 로딩되어 실행되는 짧은 시간 동안 흰 페이지가 나타날 수 있음

➡️ 이런 문제들은 서버 사이드 렌더링(server-side-rendering)을 통해 해결 가능

2. 프로젝트 준비 및 기본적인 사용법

1) 새 프로젝트 생성

$ yarn create react-app router-tutorial

2) 생성한 프로젝트 디렉터리로 이동 후 리액트 라우터 라이브러리 설치

$ cd router-tutorial
$ yarn add react-router-dom

3) 프로젝트에 라우터 적용

  • src/index.js 파일에서 react-router-dom에 내장되어 있는 BrowserRouter라는 컴포넌트를 사용하여 감싸면 프로젝트에 라우터 적용됨
  • 이 컴포넌트는 웹 애플리케이션에 HTML5의 History API를 사용하여 페이지를 새로고침하지 않고도 주소를 변경하고, 현재 주소에 관련된 정보를 props로 쉽게 조회하거나 사용할 수 있도록 해줌

src/index.js 파일

import React from ‘react‘;
import ReactDOM from ‘react-dom‘;
import { BrowserRouter } from ‘react-router-dom‘;
import./index.css‘;
import App from./App‘;
import * as serviceWorker from./serviceWorker‘;

ReactDOM.render(
  <BrowserRouter>
    <App />
  </BrowserRouter>,
  document.getElementById(‘root‘)
);

serviceWorker.unregister();

4) 라우트로 사용할 페이지 컴포넌트 생성

  • Home 컴포넌트: 사용자가 웹 사이트에 들어왔을 때 처음 보여 줄 컴포넌트
  • About 컴포넌트: 웹 사이트 소개

src 디렉터리에 Home.js 생성

import React from 'react';
 
const Home = () => {
  return (
    <div>
      <h1></h1>
      <p>, 그 페이지는 가장 먼저 보여지는 페이지.</p>
    </div>
  );
};

export default Home;

src 디렉터리에 About.js 생성

import React from 'react';
 
const About = () => {
  return (
    <div>
      <h1>소개</h1>
      <p>이 프로젝트는 리액트 라우터 기초를 실습해 보는 예제 프로젝트입니다.</p>
    </div>
  );
};
 
export default About;

5) Route 컴포넌트로 특정 주소에 컴포넌트 연결

  • Route 컴포넌트: 사용자의 현재 경로에 따라 다른 컴포넌트 ➡ 경로 규칙에 따라 어떤 컴포넌트를 보여 줄지 정의

예시: <Route path=“주소규칙“ component={보여 줄 컴포넌트} />

  • App.js 파일에서 기존 코드를 모두 제거 후, Route 컴포넌트를 사용하여 Home 컴포넌트 or About 컴포넌트를 보여 주도록 설정하기
import React from ‘react‘;
import { Route } from ‘react-router-dom‘;
import About from./About‘;
import Home from./Home‘;
 
const App = () => {
  return (
    <div>
      <Route path=/“ component={Home} />
      <Route path=/about“ component={About} />
    </div>
  );
};

export default App;

6) 실행

  • 터미널에 yarn start 입력해서 개발 서버 시작하기 ➡ Home 컴포넌트가 첫 화면에 나타남

⬇ 주소창에 localhost:3000/about 입력하면 About 컴포넌트만 나오는 것이 아니라 두 컴포넌트 모두 나타남

이유: /about 경로가 / 규칙에도 일치하기 때문

📍 Home을 위한 Route 컴포넌트 사용할 때 exact라는 props를 true로 설정하면 해결 가능

app.js 파일

import React from ‘react‘;
import { Route } from ‘react-router-dom‘;
import About from./About‘;
import Home from./Home‘;

const App = () => {
  return (
    <div>
      <Route path=/“ component={Home} exact={true} />
      <Route path=/about“ component={About} />
    </div>
  );
};

export default App;

다시 브라우저를 확인해보면 이제 about 컴포넌트만 뜸!


7) Link 컴포넌트를 사용해 다른 주소로 이동하기

  • Link 컴포넌트: 클릭하면 다른 주소로 이동시켜 주는 컴포넌트
  • Link 컴포넌트를 사용하여 페이지를 전환하면, 페이지를 새로 불러오지 않고 애플리케이션은 그대로 유지한 상태에서 HTML5 History API를 사용하여 페이지의 주소만 변경해줌
  • Link 컴포넌트 자체는 a 태그로 이루어져 있지만, 페이지 전환을 방지하는 기능이 내장
  • Link 컴포넌트 사용 예시: <Link to="주소">내용</Link>

+) 일반 웹 애플리케이션에서는 a 태그를 사용하여 페이지를 전환하는데, 리액트 라우터를 사용할 때는 이 태그를 직접 사용하면 안됨. ( a 태그는 페이지를 전환하는 과정에서 페이지를 새로 불러오기 때문에 애플리케시연이 들고 있던 상태들을 모두 날리게 됨. 렌더링된 컴포넌트들도 모두 사라지고 다시 처음부터 렌더링하게 됨.)

  • App 컴포넌트에서 " / ", " /about" 경로로 이동하는 Link 컴포넌트 만들기

App.js

import React from ‘react‘;
import { Route, Link } from ‘react-router-dom‘;
import About from./About‘;
import Home from./Home‘;

const App = () => {
  return (
    <div>
      <ul>
        <li>
          <Link to=/></Link>
        </li>
        <li>
          <Link to=/about“>소개</Link>
        </li>
      </ul>
      <hr />
      <Route path=/“ component={Home} exact={true} />
      <Route path=/about“ component={About} />
    </div>
  );
};

export default App;


이제 페이지 상단에 있는 링크를 누르면 페이지가 전환됨.



3. Route 하나에 여러 개의 path 설정하기

  • Route 하나에 여러 개의 path를 지정하는 것은 최신 버전의 리액트 라우터 v5부터 적용된 기능.
    이전 버전에서 여러 개의 path에 같은 컴포넌트를 보여 줄 때
import React from ‘react‘;
import { Route } from ‘react-router-dom‘;
import About from./About‘;
import Home from./Home‘;

const App = () => {
  return (
    <div>
      <Route path=/“ component={Home} exact={true} />
      <Route path=/about“ component={About} />
      <Route path=/info“ component={About} />
    </div>
  );
};

export default App;

이렇게 Route를 두 번 사용하는 대신, path props를 배열로 설정해주면 여러 경로에서 같은 컴포넌트를 보여 줄 수 있음

import React from 'react';
import { Route } from 'react-router-dom';
import About from './About';
import Home from './Home';
 
const App = () => {
  return (
    <div>
      <Route path="/" component={Home} exact={true} />
      <Route path={['/about', '/info']} component={About} />
    </div>
  );
};
 
export default App;


4. URL 파라미터와 쿼리

페이지 주소를 정의할 때 유동적인 값을 전달하고 싶을 때는 파라미터쿼리로 분리

  • 파라미터 예시: /profiles/velopert
  • 쿼리 예시: /about?details=true

일반적으로 파라미터는 특정 아이디 혹은 이름을 사용하여 조회할 때 사용, 쿼리는 키워드를 검색하거나 페이지에 필요한 옵션을 전달할 때 사용

URL 파라미터

  • Profile 컴포넌트: Profile 페이지에서 파라미터 사용
  • /profile/velopert와 같은 형식으로 뒷부분에 유동적인 username 값을 넣어 줄 때 해당 값을 props로 받아 와서 조회
import React from ‘react‘;

const data = {
  velopert: {
    name: ‘김민준‘,
    description: ‘리액트를 좋아하는 개발자‘
  },
  gildong: {
    name: ‘홍길동‘,
    description: ‘고전 소설 홍길동전의 주인공‘
  }
};

const Profile = ({ match }) => {
  const { username } = match.params;
  const profile = data[username];
  if (!profile) {
    return <div>존재하지 않는 사용자입니다.</div>;
  }
  return (
    <div>
      <h3>
        {username}({profile.name})
      </h3>
      <p>{profile.description}</p>
    </div>
  );
};

export default Profile;
  • URL 파라미터를 사용할 때는 라우터로 사용되는 컴포넌트에서 받아오는 match라는 객체 안의 params 값을 참조

    match 객체 안에는 현재 컴포넌트가 어떤 경로 규칙에 의해 보이는지에 대한 정보 들어있음

  • App 컴포넌트에서 Profile 컴포넌트를 위한 라우트 정의하기

  • 여기서 사용할 path 규칙에는 /profiles/:username이라고 넣어 주면 됨 ➡️ match.params.username 값을 통해 현재 username 값을 조회할 수 있음

  • 라우트 정의 후 상단에 각 프로필 페이지로 이동하는 링크 추가

import React from ‘react‘;
import { Route, Link } from ‘react-router-dom‘;
import About from./About‘;
import Home from./Home‘;
import Profile from./Profile‘;

const App = () => {
  return (
    <div>
      <ul>
        <li>
          <Link to=/></Link>
        </li>
        <li>
          <Link to=/about“>소개</Link>
        </li>
        <li>
          <Link to=/profile/velopert“>velopert 프로필</Link>
        </li>
        <li>
          <Link to=/profile/gildong“>gildong 프로필</Link>
        </li>
      </ul>
      <hr />
      <Route path=/“ component={Home} exact={true} />
      <Route path={[/about‘,/info‘]} component={About} />
      <Route path=/profile/:username“ component={Profile} />
    </div>
  );
};

export default App;


URL 쿼리

About 페이지에서 쿼리 받아오기

  • 쿼리는 location 객체 안에 있는 search 값에서 조회 가능
  • location 객체는 라우트로 사용된 컴포넌트에게 전달되며, 웹 애플리케이션의 현재 주소에 대한 정보를 가지고 있음

https://localhost:3000/about?detail=true 주소로 들어갔을 때의 location 객체 형태

{
  “pathname”:/about”,
  “search”:?detail=true,
  “hash”: “”
}
  • URL 쿼리를 읽을 때는 위 객체가 지닌 값 중에서 search 값(문자열)을 확인
  • URL 쿼리는 ?detail=true&another=1과 같이 문자열에 여러 가지 값을 설정해 줄 수 있음 ➡️ search 값에서 특정 값을 읽어 오기 위해서는 이 문자열을 객체 형태로 변환해줘야 함
    ➡️ qs 라이브러리 사용 (쿼리 문자열을 객체로 변환할 때 사용)

  1. qs 라이브러리 설치
    $ yarn add qs

  2. About 컴포넌트에서 location.search 값에 있는 detail이 true인지 아닌지에 따라 추가 정보를 보여 주도록 만들기

import React from ‘react‘;
import qs from ‘qs‘;

const About = ({ location }) => {
  const query = qs.parse(location.search, {
    ignoreQueryPrefix: true // 이 설정을 통해 문자열 맨 앞의 ?를 생략합니다.
  });
  const showDetail = query.detail ===true; // 쿼리의 파싱 결과 값은 문자열입니다.
  return (
    <div>
      <h1>소개</h1>
      <p>이 프로젝트는 리액트 라우터 기초를 실습해 보는 예제 프로젝트입니다.</p>
      {showDetail && <p>detail 값을 true로 설정하셨군요!</p>}
    </div>
  );
};

export default About;

3) 필요하면 값의 형태 변경

❗ 쿼리를 사용할 때는 쿼리 문자열을 객체로 파싱하는 과정에서 결과 값은 언제나 문자열이라는 점 주의

?value=1 or ?value=true와 같이 숫자나 논리 자료형(boolean)을 사용한다고 해서 해당 값이 원하는 형태로 변환되지 않고 "1", "true"처럼 문자열 형태로 받아짐
➡️ 숫자를 받아 와야 하면 parseInt, 논리 자료형 값을 사용해야 하면 정확히 "true" 문자열이랑 일치하는지 확인



5. 서브 라우트

  • 서브 라우트: 라우트 내부에 또 라우트를 정의 ➡️ 라우트로 사용하고 있는 컴포넌트 내부에 Route 컴포넌트를 또 사용해주면 됨

  • 기존의 App 컴포넌트에서는 두 종류의 프로필 링크 보여줌 ➡️ 이를 잘라내서 프로필 링크를 보여주는 Profiles 라우트 컴포넌트를 만들고, 그 안에서 Profile 컴포넌트를 서브 라우트로 사용


profiles.js

import React from 'react';
import { Link, Route } from 'react-router-dom';
import Profile from './Profile';
 
const Profiles = () => {
  return (
    <div>
      <h3>사용자 목록:</h3>
      <ul>
        <li>
          <Link to="/profiles/velopert">velopert</Link>
        </li>
        <li>
          <Link to="/profiles/gildong">gildong</Link>
        </li>
      </ul>
 
      <Route
        path="/profiles"
        exact
        render={() => <div>사용자를 선택해 주세요.</div>}
      />
      <Route path="/profiles/:username" component={Profile} />
    </div>
  );
};
 
export default Profiles;
  • 위 코드에서 첫 번째 Route 컴포넌트에는 component 대신 render라는 props 넣어 줌.

  • 컴포넌트 자체를 전달하는 것이 아니라, 보여 주고 싶은 JSX를 넣어 줄 수 있음.

  • 지금처럼 따로 컴포넌트를 만들기 애매한 상황에 사용하거나 컴포넌트에 props를 별도로 넣어 주고 싶을 때도 사용 가능

  • JSX에서 props를 설정할 때 값을 생략하면 자동으로 true 설정

ex) 현재 Profile 컴포넌트의첫 번째 Route에서 exact={true} 대신 그냥 exact라고만 적어 줬지만 의미는 같음


App.js

기존 App 컴포넌트에 있던 프로필 링크를 지우고 Profiles 컴포넌트를 /profiles 경로에 연결 & 해당 경로로 이동하는 링크 추가

import React from ‘react‘;
import { Route, Link } from ‘react-router-dom‘;
import About from./About‘;
import Home from./Home‘;
import Profiles from./Profiles‘;

const App = () => {
  return (
    <div>
      <ul>
        <li>
          <Link to=/></Link>
        </li>
        <li>
          <Link to=/about“>소개</Link>
        </li>
        <li>
          <Link to=/profiles“>프로필</Link>
        </li>
      </ul>
      <hr />
      <Route path=/“ component={Home} exact={true} />
      <Route path={[/about‘,/info‘]} component={About} />
      <Route path=/profiles“ component={Profiles} />
    </div>
  );
};

export default App;



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

1) history

  • history 객체: 라우트로 사용된 컴포넌트에 match, location과 함께 전달되는 props 중 하나 ➡️ 이 객체를 통해 컴포넌트 내에 구현하는 메서드에서 라우터 API를 호출할 수 있음

history 활용 예) 특정 버튼을 눌렀을 때 뒤로 가기, 로그인 후 화면 전환, 다른 페이지로 이탈하는 것을 방지


HistorySample.js 컴포넌트 생성

import React, { Component } from ‘react‘;

class HistorySample extends Component {
  // 뒤로 가기
  handleGoBack = () => {
    this.props.history.goBack();
  };
 
  // 홈으로 이동
  handleGoHome = () => {
    this.props.history.push(/);
  };
 
  componentDidMount() {
    // 이것을 설정하고 나면 페이지에 변화가 생기려고 할 때마다 정말 나갈 것인지를 질문함
    this.unblock = this.props.history.block(‘정말 떠나실 건가요?);
  }
 
  componentWillUnmount() {
    // 컴포넌트가 언마운트되면 질문을 멈춤
    if (this.unblock) {
      this.unblock();
    }
  }

render() {
    return (
      <div>
        <button onClick={this.handleGoBack}>뒤로</button>
        <button onClick={this.handleGoHome}>홈으로</button>
      </div>
    );
  }
}

export default HistorySample;

App.js
/history 경로에 해당 컴포넌트가 보이도록 설정

import React from ‘react‘;
import { Route, Link } from ‘react-router-dom‘;
import About from./About‘;
import Home from./Home‘;
import Profiles from./Profiles‘;
import HistorySample from./HistorySample‘;

const App = () => {
return (
  <div>
      <ul>
        <li>
          <Link to=/></Link>
        </li>
        <li>
          <Link to=/about“>소개</Link>
        </li>
        <li>
          <Link to=/profiles“>프로필</Link>
        </li>
        <li>
          <Link to=/history“>History 예제</Link>
        </li>
      </ul>
      <hr />
      <Route path=/“ component={Home} exact={true} />
    <Route path={[/about‘,/info‘]} component={About} />
      <Route path=/profiles“ component={Profiles} />
      <Route path=/history“ component={HistorySample} />
    </div>
);
};

export default App;

링크를 눌러서 현재 페이지를 이탈하려고 할 때 아래와 같은 메시지 창이 뜸


2) withRouter

  • withRouter 함수: HoC(Higher-order Component) ➡️ 라우트로 사용된 컴포넌트가 아니어도 match, location, history 객체를 접근할 수 있게 해줌

withRouterSample.js 컴포넌트 생성

import React from ‘react‘;
import { withRouter } from ‘react-router-dom‘;
const WithRouterSample = ({ location, match, history }) => {
  return (
    <div>
      <h4>location</h4>
      <textarea
        value={JSON.stringify(location, null, 2)}
        rows={7}
        readOnly={true}
      />
      <h4>match</h4>
      <textarea
        value={JSON.stringify(match, null, 2)}
        rows={7}
        readOnly={true}
      />
      <button onClick={() => history.push(/)}>홈으로</button>
    </div>
  );
};

export default withRouter(WithRouterSample);
  • 위의 코드처럼 withRouter를 사용할 때는 컴포넌트를 내보내 줄 때 함수로 감싸 줌

  • JSON.stringify의 두 번째 파라미터와 세 번째 파라미터를 위와 같이 null, 2로 설정해 주면 JSON에 들여쓰기가 적용된 상태로 문자열이 만들어짐


Profiles 컴포넌트에 렌더링하기

import React from ‘react‘;
import { Link, Route } from ‘react-router-dom‘;
import Profile from./Profile‘;
import WithRouterSample from./WithRouterSample‘;

const Profiles = () => {
  return (
    <div>
      ()
      <WithRouterSample />
    </div>
  );
};

export default Profiles;

  • match 객체를 보면 params가 비어 있음 ➡️ withRouter를 사용하면 현재 자신을 보여 주고 있는 라우트 컴포넌트(현재 Profiles)를 기준으로 match가 전달됨

  • Profiles를 위한 라우트를 설정할 때는 path=" /profiles"라고만 입력했기 때문에 username 파라미터를 읽어 오지 못하는 상태 ➡️ WithRouterSample 컴포넌트를 Profiles에서 지우고 Profile 컴포넌트에 넣으면 match 쪽에 URL 파라미터가 제대로 보이게 됨

Profile.js

import React from ‘react‘;
import { withRouter } from ‘react-router-dom‘;
import WithRouterSample from./WithRouterSample‘;

()

const Profile = ({ match }) => {
  const { username } = match.params;
  const profile = data[username];
  if (!profile) {
    return <div>존재하지 않는 사용자입니다.</div>;
  }
  return (
    <div>
      ()
      <WithRouterSample />
    </div>
  );
};

export default withRouter(Profile);


3) Switch

  • Switch 컴포넌트: 여러 Route를 감싸서 그중 일치하는 단 하나의 라우트만을 렌더링시킴
  • Switch를 사용하면 모든 규칙과 일치하지 않을 때 보여 줄 Not Found 페이지도 구현 가능

App.js

import React from ‘react‘;
import { Route, Link, Switch } from ‘react-router-dom‘;
import About from./About‘;
import Home from./Home‘;
import Profiles from./Profiles‘;
import HistorySample from./HistorySample‘;

const App = () => {
  return (
    <div>
      <ul>
        <li>
          <Link to=/></Link>
        </li>
        <li>
          <Link to=/about“>소개</Link>
        </li>
        <li>
          <Link to=/profiles“>프로필</Link>
        </li>
        <li>
          <Link to=/history“>History 예제</Link>
        </li>
      </ul>
      <hr />
      <Switch>
        <Route path=/“ component={Home} exact={true} />
        <Route path={[/about‘,/info‘]} component={About} />
        <Route path=/profiles“ component={Profiles} />
        <Route path=/history“ component={HistorySample} />
        <Route
          // path를 따로 정의하지 않으면 모든 상황에 렌더링됨
          render={({ location }) => (
            <div>
              <h2>이 페이지는 존재하지 않습니다:</h2>
              <p>{location.pathname}</p>
            </div>
          )}
        />
      </Switch>
    </div>
  );
};

export default App;


  • NavLink: Link와 비슷. 현재 경로와 Link에서 사용하는 경로가 일치하는 경우 특정 스타일 혹은 CSS 클래스를 적용할 수 있는 컴포넌트

  • NavLink에서 링크가 활성화되었을 때의 스타일을 적용할 때는 activeStyle 값을, CSS 클래스를 적용할 때는 activeClassName 값을 props로 넣어 주면 됨


Profiles.js
Profiles에서 사용하고 있는 컴포넌트에서 Link 대신 NavLink를 사용하게 하고, 현재 선택되어 있는 경우 검정색 배경에 흰색 글씨로 스타일을 보여 주게끔 코드 수정

import React from ‘react‘;
import { NavLink, Route } from ‘react-router-dom‘;
import Profile from./Profile‘;

const Profiles = () => {
  const activeStyle = {
    background: ‘black‘,
    color: ‘white‘
  };
  return (
    <div>
      <h3>사용자 목록:</h3>
      <ul>
        <li>
          <NavLink activeStyle={activeStyle} to=/profiles/velopert“ active>
            velopert
          </NavLink>
        </li>
        <li>
          <NavLink activeStyle={activeStyle} to=/profiles/gildong“>
            gildong
          </NavLink>
        </li>
      </ul>



      ()
    </div>
  );
};

export default Profiles;

0개의 댓글