반응형

 

 

 

목차 돌아가기: binaryjourney.tistory.com/pages/ReactCRUD-create-board-tutorial

 

[React][CRUD] create-board-tutorial

code: github.com/jwlee-lnd/react-create-board jwlee-lnd/react-create-board Description(korean) : https://binaryjourney.tistory.com/pages/ReactCRUD-create-board-tutorial - jwlee-lnd/react-create-boar..

binaryjourney.tistory.com

 

 

 

 

 

9편에서는 게시글 한 개의 내용을 불러오는 것을 다뤘고 이번 편에서는 게시글 목록 전체 조회를 다룰 것이다.

 

이번 편도 꽤나 쉽다!

 

 

 

 

 

 

articleSlice 와는 다른 initialState를 쓸 것이기 때문에 slice를 새로 만들어줘야 한다.

 

 

그래서 /src/slice/ 에 boardSlice.js 파일을 만들어준다.

 

방식은 articleSlice 와 같다.

 

 

 

 

createSlice룰 import 하고 createSlice 함수를 받는 변수 boardSlice를 선언한다.

 

 

// /src/slice/boardSlice

import { createSlice } from "@reduxjs/toolkit";

export const boardSlice = createSlice({
  
});

 

 

 

 

 

그리고 createSlice 부분에 configure할 내용들을 적는다.

name, initialState, reducers 를 board 특성에 맞게 적으면 끝이다.

 

 

// boardSlice.js

export const boardSlice = createSlice({
  name: "board",
  initialState: {
    board: [],
    isLoading: true,
    isSuccess: false,
    error: null,
  },
  reducers: {
    getBoard: (state, { payload }) => {
      console.log("getBoard 액션 호출");
    },
    getBoardAsync: (state, { payload: data }) => {
      return {
        ...state,
        board: data,
        isSuccess: true,
        isLoading: false,
      };
    },
  },
});

 

 

name 은 board 이기 때문에 board 이고

 

 

initialState는 board 배열 리스트를 가져오는 것이어서 state를 하나하나 지정할 필요가 없다.

그래서 조회된 내용이 잘 가져와졌는지 확인 정도만 하는 loading, success, error 와 조회 내용 부분인 board 만 지정해주겠다.

 

 

 

그리고 뷰(BoardPage)에서 dispatch 할 액션 getBoard를 기본적으로만 만들어주고

saga에서 put할 액션 getBoardAsync를 만들어주었다.

 

saga에서 put할 때 변경될 state는 데이터가 성공적으로 조회된 상태만 내보내므로 getBoardAsync의 success는 true, loading은 false로 정해주었다.

 

 

 

 

 

 

 

saga 도 또한 /src/sagas 에 boardSaga.js 파일을 만들어준다.

 

boardSaga 에서는 board 전체 내용을 가져오는 것밖에 없기 때문에 일단 아래 코드처럼만 만들어준다.

 

 

 

// /src/sagas/boardSaga.js

import { call, put } from "redux-saga/effects";
import Axios from "axios";
import { boardActions } from "../slice/boardSlice";

export function* getBoardAsync() {
  const response = yield Axios.get(`http://localhost:4000/board/`);

  yield put(boardActions.getBoardAsync(response.data));
}

 

 

위의 코드는 데이터가 성공적으로 전송됐을 때만 실행되는 것이다.

 

그 외의 경우는 reducer를 포함하여 나중에 만들기로 한다.

 

 

 

 

 

 

이제 만든 reducer 와 saga를 묶어주는 것이 남았다.

 

boardSlice 하단에 reducer와 action을 export 해줄 코드를 적는다.

 

 

 

// boardSlice.js


export const boardReducers = boardSlice.reducer;
export const boardActions = boardSlice.actions;

 

 

 

 

 

 

그리고 rootReducer가 있는 rootSlice에서 boardReducer 를 import 하여 combineReducer로 묶어준다.

 

 

// rootSlice.js

import { combineReducers } from "redux";
import { articleReducers } from "./articleSlice";
import { boardReducers } from "./boardSlice";

const rootReducer = combineReducers({ articleReducers, boardReducers });

export default rootReducer;

 

 

 

 

 

rootSaga에 가서는 감시할 액션 타입과 호출할 함수를 import 해주고 rootWatcher 안에 적는다.

 

// rootSaga

import { takeEvery, takeLatest } from "redux-saga/effects";
import { articleActions } from "../slice/articleSlice";
import { boardActions } from "../slice/boardSlice";
import { registerArticleAsync, getArticleAsync } from "./articleSaga";
import { getBoardAsync } from "./boardSaga";

const { registerArticle, getArticle } = articleActions;
const { getBoard } = boardActions;

export default function* rootWatcher() {
  yield takeLatest(registerArticle.type, registerArticleAsync);
  yield takeEvery(getArticle.type, getArticleAsync);
  yield takeEvery(getBoard.type, getBoardAsync);
}

 

 

 

 

 

 

필요한 기능은 다 구현해놨으니 이제 뷰인 BoardPage에서 액션을 호출하면 끝이다.

 

 

BoardPage 에 useDispatch와 useEffect, useSelector를  import 한다.

 

 

// BoardPage

  const dispatch = useDispatch();

  useEffect(() => {
    dispatch(boardActions.getBoard());
  }, [dispatch]);

  const board = useSelector((state) => state.boardReducers.board);

 

 

 

화면이 로딩될 때 dispatch를 해주므로 액션 dispatch 문은 useEffect 문 안에 적어줬다.

[] 안은 현재 화면 로딩 외에 만들어놓은 것이 없으므로 사실 비워놔도 된다

(나는 ESLint 노란 줄 생기는 게 싫어서 dispatch 넣어둠).

 

그리고 useSelector로는 리듀서에서 변경된 state.boardReducers.board를 잡아온다.

 

 

 

 

 

 

프레젠테이셔널 컴포넌트로 BoardList를 만들어놓았으므로 가져온 board를 BoardList의 프로퍼티로 넣어준다.

 

 

// BoardPage

      <div>
        <BoardList board={board} />
      </div>

 

 

 

 

 

BoardPage 의 전체 코드는 다음과 같다.

 

 

// BoardPage.js

import React, { useEffect } from "react";
import { Link } from "react-router-dom";
import BoardList from "./Sections/BoardList";
import { Button, Typography } from "antd";
import { useDispatch, useSelector } from "react-redux";
import { boardActions } from "../../../slice/boardSlice";

const { Title } = Typography;

function BoardPage() {
  const dispatch = useDispatch();

  useEffect(() => {
    dispatch(boardActions.getBoard());
  }, [dispatch]);

  const board = useSelector((state) => state.boardReducers.board);

  return (
    <div style={{ maxWidth: "700px", margin: "2rem auto" }}>
      <div>
        <Title>Board Title</Title>
      </div>
      <div>
        <Link to="/register">
          <Button type="primary">New Post</Button>
        </Link>
      </div>
      <div>
        <BoardList board={board} />
      </div>
    </div>
  );
}

export default BoardPage;

 

 

 

 

 

 

BoardList 컴포넌트에서는 props로 board를 받아 map으로 안의 내용을 풀어준다.

 

테이블로 그나마 보기 좋게 만들어준다.

 

 

// BoardList.js

import React from "react";
import { Link } from "react-router-dom";

function BoardList(props) {
  console.log(props.board);

  return (
    <div>
      <table>
        <colgroup>
          <col width="10%" />
          <col width="10%" />
          <col width="40%" />
          <col width="40%" />
        </colgroup>
        <tr>
          <th>번호</th>
          <th>제목</th>
          <th>조회수</th>
        </tr>
        {props.board.map((article) => (
          <tr>
            <td>{article.id}</td>
            <Link to={`/article/${article.id}`}>
              <td>{article.title}</td>
            </Link>
            <td>{article.views}</td>
          </tr>
        ))}
      </table>
    </div>
  );
}

export default BoardList;

 

 

 

여기서 Link to 는 해당 글의 제목을 클릭하면 이동하도록 해놨다.

 

ArticlePage에서 파라미터로 articleId를 읽으므로 경로 마지막에 article.id 를 넣어준 것이다.

 

 

 

 

 

 

 

 

결과물을 보면 이것과 비슷하게 나올 것이다.

 

 

 

 

BoardPage

 

 

 

 

 

 

 

 

글을 클릭하면

 

 

이전 과정에서 ArticlePage까지 만들어놨기 때문에

 

 

ArticleDetail

 

 

해당 글 내용까지 슈루룩 들어간다.

 

 

 

 

 

 

 

 

목록으로 가는 버튼까지만 만들고 이번 편을 마무리하겠다.

 

 

ArticleDetail 컴포넌트에 필요한 라이브러리를 import 한다.

 

 

// ArticleDetail


import { Link } from "react-router-dom";
import { Button, Typography } from "antd";

const { Title } = Typography;

 

 

 

 

 

그리고 table 이 들어간 div 위에 코드를 추가한다

 

 

      <div style={{ margin: "2rem auto" }}>
        <Link to="/">
          <Button type="primary">목록으로 가기</Button>
        </Link>
      </div>
      <div style={{ textAlign: "center" }}>
        <Title>게시글</Title>
      </div>

 

 

 

 

 

ArticleDetail 의 전체 코드는 다음과 같다.

 

 

// ArticleDetail


import React from "react";
import { Link } from "react-router-dom";
import { Button, Typography } from "antd";

const { Title } = Typography;

function ArticleDetail(props) {
  return (
    <div style={{ width: "80%", margin: "3rem auto" }}>
      <div style={{ margin: "2rem auto" }}>
        <Link to="/">
          <Button type="primary">목록으로 가기</Button>
        </Link>
      </div>
      <div style={{ textAlign: "center" }}>
        <Title>게시글</Title>
      </div>
      <div>
        <table>
          <colgroup>
            <col width="10%" />
            <col width="40%" />
            <col width="10%" />
            <col width="40%" />
          </colgroup>
          <tr>
            <th>번호</th>
            <td>{props.id}</td>
            <th>조회수</th>
            <td>{props.views}</td>
          </tr>
          <tr>
            <th>제목</th>
            <td colspan="3">{props.title}</td>
          </tr>
          <tr>
            <th>내용</th>
            <td colspan="3">{props.content}</td>
          </tr>
        </table>
      </div>
    </div>
  );
}

export default ArticleDetail;

 

 

 

 

 

 

 

파일을 저장하면 화면이 이렇게 바뀌어 있을 것이다.

 

 

 

ArticleDetail

 

 

 

버튼과 목록을 클릭해보며 왔다 갔다 해보자

 

 

 

 

 

기본적인 틀은 다 만들어놓았다고 생각한다.

 

조회수 늘리기, 수정하기, 삭제, 댓글 등 세부적인 기능은 다음 편에서부터 다루겠다.

 

 

 

 

 

 

목차 돌아가기: binaryjourney.tistory.com/pages/ReactCRUD-create-board-tutorial

 

[React][CRUD] create-board-tutorial

code: github.com/jwlee-lnd/react-create-board jwlee-lnd/react-create-board Description(korean) : https://binaryjourney.tistory.com/pages/ReactCRUD-create-board-tutorial - jwlee-lnd/react-create-boar..

binaryjourney.tistory.com

 

 

반응형

+ Recent posts