본문 바로가기
React

REACT] React Router, React Media

by Fastlane 2020. 10. 12.
728x90
반응형

디바이스 스크린의 사이즈에 따라, 다른 route를 제공하는 user dashboard application을 만들어보자. 

 

Step1 - Setting Up the Project

프로젝트 시작을 위해, npx와 create-react-app을 사용하여 새로운 React application을 만든다. 

create-react-app으로 리액트 프로젝트를 생성할 때, 2가지 방법이 있다. 

첫 번째 방법 : 

npm install -g create-react-app
create-react-app my-app
cd my-app
npm start

첫 번째 방법은, creat-react-app을 글로벌 모듈로 설치한 다음, 사용하는 방법이다. 

이 방법은 모듈의 업데이트 여부가 확인이 불가능하여, 이전 버전을 사용할 수 있다. 

 

두 번째 방법 : 

npx create-react-app my-app
cd my-app
npm start

npx는 npm 5.2+ 버전의 패키지 실행 도구이다. 

npx는 모듈을 로컬에 저장하지 않고, 최신 버전의 파일을 불러와 실행시킨 후, 다시 그 파일이 없어지는 방식이다. 

create-react-app같은 보일러 플레이트 모듈을 사용할 때 효과적이다. 

 

D:\>npx create-react-app responsive-routing
npx: installed 97 in 10.57s

Creating a new React app in D:\responsive-routing.

Installing packages. This might take a couple of minutes.
Installing react, react-dom, and react-scripts with cra-template...

yarn add v1.22.4
[1/4] Resolving packages...
error An unexpected error occurred: "https://registry.yarnpkg.com/react: unable to verify the first certificate".

프로젝트 생성 시, 위와 같은 에러 발생하면, strict-ssl false 세팅 후, 다시 생성한다.  

D:\>yarn config set "strict-ssl" false
success Set "strict-ssl" to "false".
Done in 0.06s.

D:\>npx create-react-app responsive-routing

react-router-dom, react-media 모듈을 설치한다. 

cd responsive-routing
npm install react-router-dom@5.2.0 react-media@1.10.0

Bulma css framework를 추가한다. 

npm install bulma@0.6.2

index.js

import 'bulma/css/bulma.css';

Step 2 — Adding React Router

프로젝트에서 Router를 사용하기 위해, index.jsBrowserRouterreact-router-dom으로부터 import한다. 

 

//index.js
import React from 'react';
import ReactDOM from 'react-dom';
import { BrowserRouter as Router } from "react-router-dom";
import './index.css';
import App from './App';
import * as serviceWorker from './serviceWorker';
import 'bulma/css/bulma.css';

그리고 <App />을 <Router></Router>로 감싼다. 

//index.js
ReactDOM.render(
  <Router>
    <App />
  </Router>,
  document.getElementById('root')
);

Step 3 — Creating the Nav Component

페이지 중앙의 GitHub 로그를 추가한다. 

src폴더 하위에 Nav 폴더를 생성한다. 

$ mkdir src/Nav

logo.svg이미지를 추가한다. 

다음의 코드를 추가한다. 

//src/Nav/index.js
import React from 'react';
import './Nav.css';
import logo from './logo.svg';

const Nav = () => (
  <nav>
    <img src={logo} alt="Logo" />
  </nav>
);

export default Nav;

Nav.css파일을 추가한다.

nav {
  display: flex;
  justify-content: center;
  height: 50px;
  margin-bottom: 10px;
}

nav > img {
  display: block;
  width: 50px;
  height: auto;
}

App component에 Nav component를 import한다. 

//src/App.js
import React, { Component } from 'react';
import Nav from './Nav';

class App extends Component {
  render() {
    return (
      <div>
        <Nav />
      </div>
    );
  }
}

export default App;

web browser에서 열어보면, logo가 추가된 것을 확인할 수 있다. 

$ yarn start

Step 4 — Creating the UsersCard Component

user의 상세정보를 표시할 UserCard Component를 만들자. 

 

$ mkdir src/Users

UserCard.js파일을 생성한다. 

아래의 코드를 추가한다. 

//src/Users/UsersCard.js
import React from 'react';
import { Link } from 'react-router-dom';
import './UsersCard.css'

const UsersCard = ({ user, match }) => <Link to={`${match.url}/${user.id}`} className="column card">
  <img src={user.avatar} alt=""/>
  <p className="users-card__name">{user.name}</p>
  <p className="users-card__username">@{user.username}</p>
  <div className="users-card__divider"></div>
  <div className="users-card__stats">
    <div>
      <p>{user.followers}</p>
      <span>Followers</span>
    </div>
    <div>
      <p>{user.following}</p>
      <span>Following</span>
    </div>
    <div>
      <p>{user.repos}</p>
      <span>Repositories</span>
    </div>
  </div>
</Link>;

export default UsersCard;

Link component는 카드가 클릭될 때, 상세정보 view로 이동할 수 있도록 한다. 

 

UserCard id가 10009일때 Link component는 아래와 같이 URL을 만든다. 

localhost:3000/10009

localhost:3000 : 현재 URL

10009 : $user.id

 

이 정보는 렌더링 될 component로 전달된다. 

 

그 다음 UserCard.css 파일을 만들고, 다음의 styling을 추가한다. 

.card {
  border-radius: 2px;
  background-color: #ffffff;
  box-shadow: 0 1.5px 3px 0 rgba(0, 0, 0, 0.05);
  max-width: 228px;
  margin: 10px;
  display: flex;
  flex-direction: column;
  align-items: center;
  padding: 0;
}

.card img {
  width: 50px;
  height: auto;
  border-radius: 50%;
  display: block;
  padding: 15px 0;
}

.users-card__name {
  font-weight: 400;
  font-size: 16.5px;
  line-height: 1.19;
  letter-spacing: normal;
  text-align: left;
  color: #25292e;
}

.users-card__username {
  font-size: 14px;
  color: #707070;
}

.users-card__divider {
  border: solid 0.5px #efefef;
  width: 100%;
  margin: 15px 0;
}

.users-card__stats {
  display: flex;
}

.users-card__stats p {
  font-size: 20px;
}

.users-card__stats div {
  margin: 10px;
  text-align: center;
}

.users-card__stats span {
  color: #707070;
  font-size: 12px;
}

이제, UsersCard component가 완성되었다, 다음으로 이 카드들을 나열할 list가 필요하다. 

Step 5 — Creating the UsersList Component

list users를 만들기 위해, UserList component를 만들어야 한다. 

UserList.js파일을 만들고 다음의 코드를 추가한다. 

 

우선, 필요한 imports를 만든다. 

//src/Users/UsersList.js
import React from 'react';
import UsersCard from './UsersCard';
import './UsersList.css';

그 다음, users배열로부터 UserCard component를 만들 listOfUserPerRow 함수를 선언한다. 

// ...

const listOfUsersPerRow = (users, row, itemsPerRow, match) =>
  users
    .slice((row - 1) * itemsPerRow, row * itemsPerRow)
    .map(user => <UsersCard user={user} key={user.id} match={match} />);

itemsPerRow의 값만큼 columns를 만들 listOfRaws 함수를 선언한다. 

// ...

const listOfRows = (users, itemsPerRow, match) => {
  const numberOfUsers = users.length;
  const rows = Math.ceil(numberOfUsers / itemsPerRow);

  return Array(rows)
    .fill()
    .map((val, rowIndex) => (
    <div className="columns">
        {listOfUsersPerRow(users, rowIndex + 1, itemsPerRow, match)}
    </div>
  ));
};

그 다음 UsersList를 만든다. 

//...

const UsersList = ({ users, itemsPerRow = 2, match }) => (
  <div className="cards">
    <h3 className="is-size-3 has-text-centered">Users</h3>
    {listOfRows(users, itemsPerRow, match)}
  </div>
);

export default UsersList;

다음 UserList.css 파일을 만든다. 

.cards {
  margin-left: 20px;
}

.columns {
  margin-top: 0;
}

이제 UserCard들로 이루어진 UserList component를 만들었다. 다음으로 개별 user의 상세view가 필요하다. 

Step 6 — Creating the UsersDetails Component

UserList에서 하나의 UsersCard가 클릭될 때, 하나의 UsersCard는 details section하위에서 보여진다. 

 

UsersDetail.js 파일을 생성한다. 

//src/Users/UsersDetails.js
import React from 'react';
import UsersCard from './UsersCard';

const UsersDetails = ({ user, match }) => <div>
  <h3 className="is-size-3 has-text-centered">Details</h3>
    <UsersCard user={user} match={match} />
  </div>;

export default UsersDetails;

이제 UserDetails component를 만들었다. 다음으로, UserListsUsersDetails를 display하자. 

Step 7 — Creating the UsersDashboard Component

dashboard component는, UserList를 표시하고, UserCard가 클릭되었을 때, 화면 한쪽에 reload없이 UserDetails를 표시한다.

 

UserDashboard.js를 생성한다. 

//src/Users/UsersDashboard.js
import React from 'react';
import { Route } from 'react-router-dom';
import UsersList from './UsersList';
import UsersDetails from './UsersDetails';

const UsersDashboard = ({ users, user, match }) => (
  <div className="columns">
    <div className="column">
      <UsersList users={users} match={match} />
    </div>
    <div className="column">
      <Route
        path={match.url + '/:id'}
        render={props => (
          <UsersDetails
            user={
              users.filter(
                user => user.id === parseInt(props.match.params.id, 10)
              )[0]
            }
            match={match}
          />
        )}
      />
    </div>
  </div>
);

export default UsersDashboard;

카드가 클릭되었을 때, 특정 user detail을 표시하기 위해, Route component를 사용했다. 

 

이제 모든 component가 만들어졌다. 

Step 8 — Putting it All Together

이제 모두 한 곳에 모아보자. 

 

App.js로 이동한다. 

RedirectUsersDashboard를 추가한다. 

//src/App.js
import React, { Component } from 'react';
import { Route, Redirect } from 'react-router-dom';
import Nav from './Nav';
import UsersDashboard from './Users/UsersDashboard';
import './App.css';

users 배열을 포함하는 state를 추가한다. 

 

Route, UsersDashboard를 App component에 추가한다. 

  render() {
    return (

      <div className="App">
        <Nav />
        <Route
          path="/dashboard"
          render={props => (
            <UsersDashboard users={this.state.users} {...props} />
          )}
        />
        <Redirect from="/" to="/dashboard"/>
        <Redirect from="/users" to="/dashboard"/>
      </div>

    )
  };

UsersCard를 클릭하면 UsersDetails가 display된다. 

Step 9 — Setting Up Responsive Routing

디바이스 사이즈에 맞는 view를 제공할 수 있도록 수정해보자. 

wide screen으로 접속할 경우 /dashboard로 redirect되어 UsersDashboard를 보여주고 UsesCard를 클릭하면 UsersDetails가 우측에 display된다. 

small screen으로 접속할 경우 /users로 redirect되어 UsersList를 보여주고 UsesCard를 클릭하면 /users/:id로 redirect되어 UsersDetails를 보여준다. 

Switch, Media, UsersList, UsersDetails를 추가한다. 

import React, { Component } from 'react';
import { Route, Switch, Redirect } from 'react-router-dom'; // add Switch
import Media from 'react-media'; // add Media
import Nav from './Nav';
import UsersList from './Users/UsersList'; // add UsersList
import UsersDetails from './Users/UsersDetails'; // add UsersDetails
import UsersDashboard from './Users/UsersDashboard';
import './App.css';

class App extends React.Component {


  state = {
    users: [
      {
        id: 39191,
        avatar: 'https://avatars0.githubusercontent.com/u/39191?v=4',
        name: 'Peter',
        username: 'Peter',
        followers: '12k',
        following: '1k',
        repos: '1.5k'
      },
      {
        id: 39192,
        avatar: 'https://avatars0.githubusercontent.com/u/39192',
        name: 'Jake',
        username: 'Jake',
        followers: '20k',
        following: '1k',
        repos: '1.5k'
      },
      // ... other user data
    ]
  };

  render() {
    return (

      <div className="App">
        <Nav />
        <Media query="(max-width: 599px)">
          {matches =>
            matches ? (
              <Switch>
                <Route
                  exact
                  path="/users"
                  render={props => (
                    <UsersList users={this.state.users} {...props} />
                  )}
                />
                <Route
                  path="/users/:id"
                  render={props => (
                    <UsersDetails
                      user={
                        this.state.users.filter(
                          user =>
                            user.id === parseInt(props.match.params.id, 10)
                        )[0]
                      }
                      {...props}
                    />
                  )}
                />
                <Redirect from="/" to="/users"/>
                <Redirect from="/dashboard" to="/users"/>
              </Switch>
            ) : (
              <Switch>
                <Route
                  path="/dashboard"
                  render={props => (
                    <UsersDashboard users={this.state.users} {...props} />
                  )}
                />
                <Redirect from="/" to="/dashboard"/>
                <Redirect from="/users" to="/dashboard"/>
              </Switch>
            )
          }
        </Media>
      </div>

    )
  };
}

export default App;

wide screen : 

small screen : 

 

결론

React application에서 screen size 조건에 따라 다르게 rendering할 수 있는 방법을 살펴보았다. 

 

출처 : www.digitalocean.com/community/tutorials/how-to-set-up-conditional-and-responsive-routing-with-react-router-v4

 

How To Set Up Conditional and Responsive Routing with React Router v4 | DigitalOcean

Responsive routing in React involves serving different routes to users based on the viewport of their device. In this tutorial, we will show you how to implement routing and serving responsive routes in your React applications. By following this tutor

www.digitalocean.com

 

 

728x90
반응형

댓글