React의 라우팅 이해하기

전통적인 브라우저 - 서버

Screenshot 2023-06-27 at 9.29.17 PM.png

SPA(Single Page Application)

Screenshot 2023-06-27 at 9.30.12 PM.png

SPA 라우팅 과정

  1. 브라우저에서 최초에 '/' 경로로 요청을 하면,
  2. React Web App을 내려줍니다.
  3. 내려 받은 React App 에서 '/' 경로에 맞는 컴포넌트를 보여줍니다.
  4. React App 에서 다른 페이지로 이동하는 동작을 수행하면,
  5. 새로운 경로에 맞는 컴포넌트를 보여줍니다.

Recat Router는 내장 패키지가 아닙니다.

  • cra에 기본 내장된 패키지가 아닙니다.
  • react-router-dom 은 FaceBook의 공식 패키지가 아닙니다.
  • 가장 대표적인 라우팅 패키지 입니다.

# React route 설치 방법
npm i react-router-dom

실습

npx create-react-app react-router-example

npm i react-router-dom

! 300

export default function 폴더명(){

return <div>폴더명 페이지 입니다.</div>

}

그리고 App.js에 들어가서 아래와 같이 코드를 수정해주면 됩니다.

fuction App(){
	return (
		<BrowerRouter>
			<Route path="/" componment={Home}/>
			<Route path="/profile" componment={Profile}/>
			<Route path="/about" componment={About}/>
		</BrowerRouter>
	);
}

Screenshot 2023-06-27 at 10.03.22 PM.png

Screenshot 2023-06-27 at 10.04.00 PM.png

Dynamic 라우팅

:id

import { BrowserRouter, Route } from 'react-router-dom';
import Home from './pages/Home';
import Profile from './pages/Profile';
import About from './pages/About';

function App() {
  return (
    <BrowserRouter>
      <Route path="/" exact component={Home} />
      <Route path="/profile" exact component={Profile} />
      <Route path="/profile/:id" component={Profile} />
      <Route path="/about" component={About} />
    </BrowserRouter>
  );
}

export default App;

App.jsx

export default function Profile(props) {
  const id = props.match.params.id;
  console.log(id, typeof id);
  return (
    <div>
      <h2>Profile 페이지입니다.</h2>
      {id && <p>id 는 {id} 입니다.</p>}
    </div>
  );
}

profile.jsx
-id는 숫자가 아닌 문자 데이터로 받아온다.

params & query

import { BrowserRouter, Route } from 'react-router-dom';
import Home from './pages/Home';
import Profile from './pages/Profile';
import About from './pages/About';

function App() {
  return (
    <BrowserRouter>
      <Route path="/" exact component={Home} />
      <Route path="/profile" exact component={Profile} />
      <Route path="/profile/:id" component={Profile} />
      <Route path="/about" component={About} />
    </BrowserRouter>
  );
}

export default App;

App.js

// src/pages/About.jsx

export default function About(props) {
  const searchParams = props.location.search;
  console.log(searchParams); //?name=mark
  return (
    <div>
      <h2>About 페이지 입니다.</h2>
    </div>
  );
}

About.jsx

// src/pages/About.jsx

export default function About(props) {
  const searchParams = new URLSearchParams(props.location.search);
  const name = searchParams.get('name');
  console.log(name);
  return (
    <div>
      <h2>About 페이지 입니다.</h2>
      {name && <p>name 은 {name} 입니다.</p>}
    </div>
  );
}

About.jsx

// src/pages/About.jsx

import queryString from 'query-string';

export default function About(props) {
  const query = queryString.parse(props.location.search);
  const { name } = query;
  console.log(name);
  return (
    <div>
      <h2>About 페이지 입니다.</h2>
      {name && <p>name 은 {name} 입니다.</p>}
    </div>
  );
}

! 300

import { NavLink } from 'react-router-dom'
ActivateClassName, ActivateStyle

  • activeClassName, activeStyle 처럼 active 상태에 대한 스타일 지정이 가능합니다.
  • Route 의 path 처럼 동작하기 때문에 exact 가 있습니다.

import { NavLink } from "react-router-dom";

const activeStyle = { color: "green" };

export default function NavLinks() {
  return (
    <ul>
      <li>
        <NavLink to="/" exact activeStyle={activeStyle}>
          Home
        </NavLink>
      </li>
      <li>
        <NavLink to="/profile" exact activeStyle={activeStyle}>
          Profile
        </NavLink>
      </li>
      <li>
        <NavLink to="/profile/1" activeStyle={activeStyle}>
          Profile/1
        </NavLink>
      </li>
      <li>
        <NavLink
          to="/about"
          activeStyle={activeStyle}
          isActive={(match, location) =>
            match !== null && location.search === "" 
            //match의 검사 유무는 ?뒤에 까지 검사하기 위함이다.
          }
        >
          About
        </NavLink>
      </li>
      <li>
        <NavLink
          to="/about?name=mark"
          activeStyle={activeStyle}
          isActive={(match, location) =>
            match !== null && location.search === "?name=mark"
            //match의 검사 유무는 ?뒤에 까지 검사하기 위함이다.ㄴ
          }
        >
          About?name=mark
        </NavLink>
      </li>
    </ul>
  );
}

App.js
Screenshot 2023-07-01 at 3.47.41 PM.png

Js로 라우팅 이동하기

import { BrowserRouter, Route, Switch } from 'react-router-dom';
import Home from './pages/Home';
import Profile from './pages/Profile';
import About from './pages/About';
import NotFound from './pages/NotFound';
import Links from './components/Links';
import NavLinks from './components/NavLinks';
import Login from './pages/Login';

function App() {
  return (
    <BrowserRouter>
      <Links />
      <NavLinks />
      <Switch>
        <Route path="/login" component={Login} />
        <Route path="/profile/:id" component={Profile} />
        <Route path="/profile" component={Profile} />
        <Route path="/about" component={About} />
        <Route path="/" exact component={Home} />
        <Route component={NotFound} />
      </Switch>
    </BrowserRouter>
  );
}

export default App;

App.js

// src/pages/Login.jsx

export default function Login(props) {
  console.log(props);
  function login() {
    setTimeout(() => {
      props.history.push('/');
    }, 1000);
  }
  return (
    <div>
      <h2>Login 페이지 입니다.</h2>
      <button onClick={login}>로그인하기</button>
    </div>
  );
}

Login.js

// src/pages/Login.jsx

import LoginButton from '../components/LoginButton';

export default function Login() {
  return (
    <div>
      <h2>Login 페이지 입니다.</h2>
      <LoginButton />
    </div>
  );
}

Login.jsx

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

export default withRouter(function LoginButton(props) {
  console.log(props);
  function login() {
    setTimeout(() => {
      props.history.push('/');
    }, 1000);
  }
  return <button onClick={login}>로그인하기</button>;
});

LoginButton.jsx

Screenshot 2023-07-01 at 4.05.28 PM.png

// src/pages/Login.jsx

import LoginButton from '../components/LoginButton';

export default function Login(props) {
  return (
    <div>
      <h2>Login 페이지 입니다.</h2>
      <LoginButton {...props}/>
    </div>
  );
}
import { withRouter } from 'react-router-dom';

export default withRouter(function LoginButton(props) {
  console.log(props);
  function login() {
    setTimeout(() => {
      props.history.push('/');
    }, 1000);
  }
  return <button onClick={login}>로그인하기</button>;
});

Redirect

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

// jsx
<Redirect to='/' />

실습

import { BrowserRouter, Route, Switch, Redirect } from 'react-router-dom';
import Home from './pages/Home';
import Profile from './pages/Profile';
import About from './pages/About';
import NotFound from './pages/NotFound';
import Links from './components/Links';
import NavLinks from './components/NavLinks';
import Login from './pages/Login';

const isLogin = true;

function App() {
  return (
    <BrowserRouter>
      <Links />
      <NavLinks />
      <Switch>
        <Route
          path="/login"
          render={() => (isLogin ? <Redirect to="/" /> : <Login />)} // isLogin이 True 일 때, Redirect로 home으로 간다
        />
        <Route path="/profile/:id" component={Profile} />
        <Route path="/profile" component={Profile} />
        <Route path="/about" component={About} />
        <Route path="/" exact component={Home} />
        <Route component={NotFound} />
      </Switch>
    </BrowserRouter>
  );
}

export default App;


#React #FrontEnd