오늘은 그동안 공부했던 것을 바탕으로 react-router-dom 과 redux 를 이용한 페이지 구현하는 부분을 포스팅 해보겠다.
원레는 게시판을 만들어보려고 했는데 오늘은 이 부분 구현하는 데 시간을 많이 소요했다.ㅎ.ㅎ
위와 같이 Write 버튼 클릭 시 글 작성 페이지로 이동되며, footer 부분의 버튼 중 Write 버튼이 사라지게 되는 부분이다.
먼저 디렉토리는 아래와 같다.
먼저, redux 를 사용하기 위해 index.js 에서 store 를 생성하고, Provider 로 App.js 를 감싸준다.
src/index.js
import React from 'react';
import ReactDOM from 'react-dom';
import { Provider } from 'react-redux';
import { createStore } from 'redux';
import rootReducer from '@modules/rootReducer';
import App from '@src/App';
const store = createStore(rootReducer);
ReactDOM.render(
<Provider store={store}>
<App />
</Provider>
, document.getElementById('app')
);
App.js 에서는 react-router-dom 을 사용하기 위해 Router로 감싸주고, 호출되는 path 주소에 따라 나타낼 component 를 지정해 주었다.
가장 아랫부분은 Footer 컴포넌트를 넣어 따로 관리해 준다.
src/App.js
import React from 'react';
import { BrowserRouter as Router, Switch, Route } from 'react-router-dom';
import '@css/style.css';
import BoardList from '@components/BoardList';
import BoardNew from '@components/BoardNew';
import BoardContent from '@components/BoardContent';
import Footer from '@components/Footer';
function App () {
return (
<div className="App">
<Router>
<div>
<Switch>
<Route path='/' component={BoardList} exact />
<Route path='/BoardNew' component={BoardNew} exact />
<Route path='/BoardContent' component={BoardContent} exact />
</Switch>
</div>
<div>
<Footer />
</div>
</Router>
</div>
)
}
export default App;
path 마다 열릴 컴포넌트들을 각각 생성하여 작성해준다.
src/components/BoardList.js
import React from 'react';
function BoardList() {
return(
<div>
<h2>게시판</h2>
<div>
<table className='listTable'>
<tbody>
<tr>
<td className='listTableIndex th'>index</td>
<td className='listTableTitle th'>title</td>
</tr>
<tr>
<td className='listTableIndex'></td>
<td className='listTableTitle noData'>작성된 글이 없습니다.</td>
</tr>
</tbody>
</table>
</div>
</div>
)
}
export default BoardList;
src/components/BoardNew.js
import React from 'react';
function BoardNew() {
return(
<div>
<h2>글 작성</h2>
<div>
<form>
<div>
<input type='text' className='inputTitle' placeholder='제목을 입력하세요' />
</div>
<div>
<textarea className='inputContent' placeholder='내용을 입력하세요' />
</div>
<div>
<button type='submit'>submit</button>
</div>
</form>
</div>
</div>
)
}
export default BoardNew;
src/components/BoardContent.js
import React from 'react';
function BoardContent() {
return(
<div>
<h2>상세보기</h2>
<div>
</div>
</div>
)
}
export default BoardContent;
BoardContent 는 컴포넌트만 만들어 두었다.ㅎㅎ
CSS 는 아래와 같다.
public/css/style.css
ul {
list-style-type: none;
}
ul li {
display:inline;
margin: 15px;
}
table {
font-family: Arial, Helvetica, sans-serif;
}
.listTable{
border-collapse: collapse;
}
.listTable tbody tr td{
border: 1px solid rgb(50, 50, 50);
padding: 5px;
}
.listTableIndex {
width: 100px;
}
.listTableTitle {
width: 350px;
}
.th {
text-align: center;
}
.noData {
color: rgb(150, 150, 150);
text-align: center;
}
.inputTitle {
width: 350px;
font-size: 16px;
margin: 5px;
}
.inputContent {
width: 350px;
margin: 5px;
font-size: 16px;
height: 200px;
}
이제 Footer 컴포넌트와 버튼 컴포넌트들도 만들어준다.
src/components/Footer.js
import React from 'react';
import ButtonHome from '@components/ButtonHome';
import ButtonWrite from '@components/ButtonWrite';
function Footer() {
return(
<div>
<hr />
<nav>
<ul>
<li><ButtonHome /></li>
<li><ButtonWrite /></li>
</ul>
</nav>
</div>
);
}
export default Footer;
src/components/ButtonHome.js
import React from 'react';
import { Link } from 'react-router-dom';
function ButtonHome() {
return(
<Link to='/'>
<button>
Home
</button>
</Link>
);
}
export default ButtonHome;
src/components/ButtonWrite.js
import React from 'react';
import { Link } from 'react-router-dom';
function ButtonHome() {
return(
<Link to='/BoardNew'>
<button>
Write
</button>
</Link>
);
}
export default ButtonHome;
ButtonHome.js 와 ButtonWrite 에서 버튼을 Link 로 감싸고, to= 에 path 를 넣어 주었다. 이 path 는 App.js 에서 컴포넌트를 호출할 수 있도록 한다.
/BoardContent 는 BoardList 에서 글 제목 클릭 시 구현될 상세보기 페이지 이므로 굳이 하지 않아도 상관없다.
이제 Footer.js 에서 uri 별로 Write버튼이 보일지 말지를 결정하기 위해 버튼이 클릭될 때마다 reducer를 호출하여 변경 될 uri 를 store 에 저장할 수 있도록 할 것이다.
index.js 에서 생성한 store(rootReducer) 를 생성해준다.
src/modules/rootReducer.js
import { combineReducers } from 'redux';
import uriReducer from '@modules/uriReducer';
const rootReducer = combineReducers({
uriReducer
});
export default rootReducer;
rootReducer 생성 없이 uriReducer 로 바로 연결 해줄 수도 있지만, 나는 boardReducer 도 추가할 예정이기 때문에 rootReducer 로 combineReducers 를 사용하여 합쳐주었다.
이제 uriReducer.js 를 생성하고 작성해준다.
src/modules/uriReducer.js
// action type 설정
const URI_SAVE = 'URI_SAVE';
// 버튼 클릭 시 호출될 함수
export const uriSave = (inputData) => ({
type: URI_SAVE,
inputData: inputData
})
// data 초기화
const initialState = {
inputData: '/'
}
// store 에 실질적으로 저장해주는 reducer
export default function uriReducer(state = initialState, action){
switch(action.type) {
case URI_SAVE:
return Object.assign({}, state, {
inputData: action.inputData
})
default:
return state
}
}
위와 같이 간단하게 uriReducer 를 작성했다.
위에서 작성한 uriSave() 함수를 호출해줄 버튼 컴포넌트들에 dispatch를 추가해준다.
src/components/ButtonHome.js
import React from 'react';
import { Link } from 'react-router-dom';
import { useDispatch } from 'react-redux';
import { uriSave } from '@modules/uriReducer'
function ButtonHome() {
// 함수형 컴포넌트에서 dispatch 하기 위해 사용
const dispatch = useDispatch();
// reducer의 uriSave 함수를 호출
function onClick() {
dispatch(uriSave('/'))
}
return(
<Link to='/'>
<button onClick={onClick}>
Home
</button>
</Link>
);
}
export default ButtonHome;
write 버튼도 동일하게 작성한다.
src/components/ButtonWrite.js
import React from 'react';
import { Link } from 'react-router-dom';
import { useDispatch } from 'react-redux';
import { uriSave } from '@modules/uriReducer';
function ButtonHome() {
const dispatch = useDispatch();
function onClick() {
dispatch(uriSave('/BoardNew'))
}
return(
<Link to='/BoardNew'>
<button onClick={onClick}>
Write
</button>
</Link>
);
}
export default ButtonHome;
이제 버튼이 클릭 될때마가 reducer의 함수를 호출하고 store 에 상태가 저장될 것이다.
Footer 컴포넌트에서 store 의 상태가 변경될 때마다 state 를 전달받도록 구독하고, state 에 따라 write 버튼을 보여줄 지 말지 결정할 수 있다.
src/components/Footer.js
import React from 'react';
import { useSelector } from 'react-redux';
import ButtonHome from '@components/ButtonHome';
import ButtonWrite from '@components/ButtonWrite';
function Footer() {
// store 의 상태가 바뀔 때마다 상태를 받아온다.
const uri = useSelector(state => state.uriReducer.inputData)
return(
<div>
<hr />
<nav>
<ul>
<li><ButtonHome /></li>
// 받아온 상태가 '/BoardNew' 가 아닐때만 버튼을 보여준다.
{uri !== '/BoardNew' ?
<li><ButtonWrite /></li> :
<li></li>
}
</ul>
</nav>
</div>
);
}
export default Footer;
이제 npm start 로 프로젝트를 실행하면 아래와 같이 구동 될 것이다.
다음 게시물은 게시글을 추가하고 삭제하는 기능을 추가 해보도록 하겠다.
'React' 카테고리의 다른 글
[React] redux를 이용하여 게시판 만들기(2) - 떽떽대는 개발공부 (0) | 2021.01.26 |
---|---|
[React] redux 를 이용하여 게시판 만들기(1) - 떽떽대는 개발공부 (0) | 2021.01.25 |
[React] express 를 이용하여 서버사이드렌더링 - 떽떽대는 개발공부 (0) | 2021.01.23 |
[React] redux 를 이용한 예제 - 떽떽대는 개발공부 (0) | 2021.01.22 |
[React] props 전달받기 예제 - 떽떽대는 개발공부 (0) | 2021.01.21 |
댓글