본문 바로가기
React

[React] react, redux 를 사용하여 게시판 만들기 - 떽떽대는 개발공부

by 떽이 2021. 1. 19.

본격적인 리액트 공부를 하기 위해 구글링을 하다 아래의 블로그에서 게시판 만드는 것을 따라 해 보았다.

mjn5027.tistory.com/35

 

[ React ] 리액트 Redux 로 게시판 만들어보기

이번 포스팅에선 리덕스를 이용해 게시판의 기본적인 Create, Read, Update, Delete 구현을 다룬다. ​ 공부하며 간단히 만들어본거라 설명이 미약한 점 참고해주시길. ​ 먼저 프로젝트를 만들고 리덕

mjn5027.tistory.com

이해가 될듯 말듯 알쏭달쏭한 상태에서 router 를 이용하여 페이지 이동할 수 있는 기능을 추가 구현해 볼까 한다.

redux 관련 부분은 상기의 페이지에서 확인하면 될 것이다. 이번 글에서는 router 사용을 중점으로 했다.

내가 공부했던 Router 글은 아래와 같다.

2021/01/04 - [React] - [React] Router 를 사용하여 페이지 접근하기-떽떽대는 개발공부

 

[React] Router 를 사용하여 페이지 접근하기-떽떽대는 개발공부

Single Page Application(SPA) 서버로부터 새로운 페이지를 불러오지 않고 현재의 페이지에 컴포넌트를 통해 동적으로 다시 작성하여 클라이언트와 소통하는 웹 애플리케이션이다. 필요한 모든 소스는

ddeck.tistory.com

 

 

 

 

폴더 구조는 아래와 같이 구성하였다.

먼저 Router를 사용하기 위해 react-router-dom 를 install 한다.

$ npm i react-router-dom

 

설치가 완료 되었으면 App.js 에 BrowserRouter 를 추가하여 Container.js 를 감싸준다.

src/App.js

import React from 'react';
import Container from '@container/Container';
import { BrowserRouter } from 'react-router-dom';

function App() {
  return (
    <div>
      <BrowserRouter>
        <Container /> 
      </BrowserRouter>
    </div>
  )
}

export default App;

 

이전 router 공부할 때엔 하나의 화면에서 구현을 했으므로 화면 안에서 <Router>로 감싸 주었으나, 이번엔 페이지 밖에서 묶어주었다.

src/container/Container.js

import React from 'react';
import {BrowserRouter as Route, Switch} from 'react-router-dom';

import BoardList from '@container/BoardList';
import BoardNew from '@container/BoardNew';
import BoardContent from '@container/BoardContent';

import HomeButton from '@components/HomeButton';
import WriteButton from '@components/WriteButton';

function Container() {
    return (
        <div>
            <div>
                <Switch>
                    <Route path='/' exact component={BoardList}/>
                    <Route path='/BoardNew' exact component={BoardNew} />
                    <Route path='/BoardContent' component={BoardContent} />
                </Switch>
            </div>
            <div>
                <HomeButton />
                <WriteButton />
            </div>
        </div>
    );
}

export default Container;

 

먼저, container.js 는 위와 같이 구성되었다.

Switch 로 route 별로 나타낼 페이지 섹션을 주었고, 아래에는 home 버튼과 write 버튼을 추가하여 줄 것이다.

src/components/HomeButton.js

import React from 'react';
import { BrowserRouter as Link } from 'react-router-dom';

function HomeButton() {
    return (
        <button>
            <Link to='/'>
                Home
            </Link>
        </button>
    );
}

export default HomeButton;

 

src/components/WriteButton.js

import React from 'react';
import { BrowserRouter as Link } from 'react-router-dom';

function WriteButton() {
    return (
        <button>
            <Link to='/BoardNew'>
                Write
            </Link>
        </button>
    );
}

export default WriteButton;

 

간단하게 버튼 두개를 생성하였다.

버튼 클릭 시 router 를 이용하여 페이지를 이동하기 위해 Link 기능을 추가하였다.

Link 에서 지정한 path 로 페이지가 이동되면 Container.js 페이지에서 해당 component 를 불러와 페이지를 구현할 것이다.

먼저, 글 작성 페이지를 구현할텐데 글 작성 페이지에서 save 버튼을 클릭했을 때 함수 사용을 하기 위해 container.js 에서 먼저 함수를 작성해준다.

src/container/Container.js

import React, {useState} from 'react';
import BoardList from '@container/BoardList';
import BoardNew from '@container/BoardNew';
import BoardContent from '@container/BoardContent';
import { useDispatch, useSelector } from 'react-redux';
import { boardSave } from '@module/boardReducer';
import HomeButton from '@components/HomeButton';
import WriteButton from '@components/WriteButton';

import {BrowserRouter as Route, Switch} from 'react-router-dom';


function Container() {

    // State
    let [inputData, setInputData] = useState({
        boardId: '',
        boardTitle: '',
        boardContent: ''
    });

    const dispatch = useDispatch();

	// 글 작성 페이지에서 onSave 를 호출하면 action 에 dispatch 됨
    const onSave = (saveData) => dispatch(boardSave(saveData));

	// 글 작성 페이지에서 input value 값이 변할 때마다 값 변경
    const changeInput = (e) => {
        setInputData({
            ...inputData,
            [e.target.name]: e.target.value
        })
    }
	
    // 글 작성 페이지에서 save 버튼 클릭 시 input 란 reset
    const resetForm = () => {
        setInputData({
            boardId: '',
            boardTitle: '',
            boardContent: ''
        })
    }

    return (
        <div>
            <div>
                <Switch>
                    <Route path='/' exact component={BoardList}/>
                    <Route path='/BoardNew' 
                    	   exact 
                           component={() => 
                           		<BoardNew onSave={onSave} 
                                		  inputData={inputData} 
                                          changeInput={changeInput} 
                                          resetForm={resetForm}  
                                 />
                            } 
                    />
                    <Route path='/BoardContent' component={BoardContent} />
                </Switch>
            </div>
            <div>
                <HomeButton />
                <WriteButton />
            </div>
        </div>
    );
}

export default Container;

 

글 작성 페이지에서 사용할 수 있도록 함수 3개와 InputData를 props 로 넘겨줄 것이다.

router 사용 시 props 값을 넘겨주기 위해서는 함수형으로 전달 해주어야만 props 값이 전달된다.

그렇지 않으면 전달되지 않아서 애먹을 것이다.

src/container/BrandNew.js

import React from 'react';

function BoardNew({ onSave, changeInput, inputData, resetForm }) {

    const saveBtnClick = (e) => {
        e.preventDefault();
        onSave(inputData);
        resetForm();
    }

    return (
        <>
            <div width="50">
                <form onSubmit={saveBtnClick}>
                    <div>
                        제목 : <input type="text" name="boardTitle" onChange={changeInput} value={inputData.boardTitle} />
                    </div>
                    <div>
                        내용 : <input type="text" name="boardContent"  onChange={changeInput} value={inputData.boardContent} />
                    </div>
                    <input type="hidden" name="boardId" onChange={changeInput} value={inputData.boardId} />
                    <button type="submit" >신규 게시글 저장</button>
                </form>
            </div>
        </>
    )
};

export default BoardNew;

 

container.js 에서 넘겨받은 props 값으로 글 작성 페이지를 만들어준다.

list 구현은 넘겨받는 props 값 없이 해당 페이지에서 구현할 것이다.

src/container/BoardList.js

import React from 'react';
import { BrowserRouter as Link } from 'react-router-dom';

import { boardRemove } from '@module/boardReducer';
import { useDispatch, useSelector } from 'react-redux';

function BoardList() {

    const dispatch = useDispatch();

	// 삭제 버튼 클릭 시 action 에 dispatch 해줌
    const onRemove = (boardId) => dispatch(boardRemove(boardId));

    // 현재 store 에 있는 board field 를 구독
    const {boards} = useSelector(state => state.boardReducer);

    return (
        <div>
            <table border="1">
                <tbody>
                    <tr align="center">
                        <td width="50">번호</td>
                        <td width="100">제목</td>
                        <td width="200">내용</td>
                    </tr>
                    {boards.map(row =>(  
                      <tr>
                          <td><Link to={`/BoardContent/${row.boardId}/${row.boardTitle}/${row.boardContent}`}>{row.boardId}</Link></td>
                          <td><Link to={`/BoardContent/${row.boardId}/${row.boardTitle}/${row.boardContent}`}>{row.boardTitle}</Link></td>
                          <td><Link to={`/BoardContent/${row.boardId}/${row.boardTitle}/${row.boardContent}`}>{row.boardContent}</Link></td>
                          <td><button onClick={() => onRemove(row.boardId)}>삭제</button></td>
                      </tr>
                    ))}
                </tbody>
            </table>
        </div>
    )
}

export default BoardList;

 

list 오른쪽에 삭제 버튼을 구현하기 위해 onRemove 함수를 사용하여 action 에 dispatch 해 주었다.

글 리스트에서 제목이나 내용을 클릭하면 content 페이지로 이동하기 위해 (get 방식을 사용할 것이다)

Link 를 사용하여 boardId, boardTitle, boardContent 를 url 에 추가하였다.

이제 글을 클릭했을 때 detail 을 보여주는 페이지를 작성한다.

src/container/BoardContent.js

import React from 'react';

function BoardContent() {

    const boardId_temp = decodeURI(window.location.href).split('http://localhost:3000/BoardContent/').reverse()[0];
    const boardId = boardId_temp.split('/')[0];

    const boardTitle_temp = decodeURI(window.location.href).split(`http://localhost:3000/BoardContent/${boardId}/`).reverse()[0];
    const boardTitle = boardTitle_temp.split('/')[0];

    const boardContent_temp = decodeURI(window.location.href).split(`http://localhost:3000/BoardContent/${boardId}/${boardTitle}/`).reverse()[0];
    const boardContent = boardContent_temp.split('/')[0];
    
    return (
        <div>
            <table border="1">
                <tbody>
                    <tr align="center">
                        <td width="50">{boardId}</td>
                        <td width="300">{boardTitle}</td>
                    </tr>
                    <tr>
                        <td colspan="2" width="350">{boardContent}</td>
                    </tr>
                </tbody>
            </table>
        </div>
    )
}

export default BoardContent;

 

여기에서는 prop 값을 get 방식으로 받아왔기 때문에 url 을 split 해서 값을 저장하였다.

이렇게 하면 모든 페이지 구현이 완료 되었을 것이다.

뭔가 미흡한 부분이 있어서 router 사용으로 prop 값을 넘기고, 받는 부분에 대해서는 조금 더 공부 할 생각이다.

일단 오늘의 공부는 여기까지..

 

 

 

댓글