디바이스 스크린의 사이즈에 따라, 다른 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.js에 BrowserRouter를 react-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를 만들었다. 다음으로, UserLists와 UsersDetails를 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로 이동한다.
Redirect와 UsersDashboard를 추가한다.
//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할 수 있는 방법을 살펴보았다.
'React' 카테고리의 다른 글
REACT] Bulma css framework (0) | 2020.10.12 |
---|---|
React] 배열 렌더링 How To Render Arrays in React (0) | 2020.10.08 |
React 게시판 만들기 : 게시글 작성, 조회 (6) (1) | 2020.10.05 |
React 게시판 만들기 : 파일업로드 multer (5) (0) | 2020.10.05 |
React 게시판 만들기 : React-Quill (4) (0) | 2020.09.29 |
댓글