오늘은 그동안 공부했던 것을 바탕으로 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 |
댓글