메인 페이지 개발일지 [1] - react-redux 개념잡기

최원빈·2022년 10월 17일
0

분실물 페이지 제작 이후 메인 페이지의 컴포넌트들을 개발하였다.

이것이 코인 메인 페이지...!

대부분의 컴포넌트에서 리덕스를 사용해 API로 받아오는 데이터를 핸들링했지만, 대표적으로 하단부의 '게시판 별 최신 글' (이하 board list) 를 제작할 때 react-redux가 어떻게 굴러가는지 와닿았던 것 같다.


우선 설계를 하기 위해 구조를 짜야 했다.
Board list의 모든 게시판들은 API호출을 통해 글을 받아올 수 있다.
컨테이너에서 액션을 dispatch해서 redux의 각각의 state에 담을 것이다.

const initialState = {
  notice: [],
  free: [],
  job: [],
  anonymous: [],
  question: [],
  loading: false,
  error: null
}

이 데이터들을 받아오는 action을 각 게시판의 id를 통해서 5번 호출해 값들을 받아오면 될 것 같았다.

useEffect(() => {
  dispatch(getBoardData(1)) // 인자는 각 게시판의 id
  dispatch(getBoardData(2))
  dispatch(getBoardData(3))
  dispatch(getBoardData(4))
  dispatch(getBoardData(5))
}, [])

문제는 코드가 척 보기에도 안좋아보이고... 최상단의 최근게시물과 액션이 겹치는 것이 문제였다.

최근게시물을 뽑아주는 API가 따로 없어서 각 Board마다 데이터를 받아온 후, 최신순으로 나열하는 방식으로 만들었다.

이미 상단에서 위같이 코드를 짰고, 하단에서도 같은 코드를 원하니 따로 action을 만들었다.

//redux-saga

function* getNewPosts() {
  try {
    const notice = yield call(boardAPI.getIndexPageArticleList, 1);
    const job = yield call(boardAPI.getIndexPageArticleList, 2);
    const free = yield call(boardAPI.getIndexPageArticleList, 3);
    const anonymous = yield call(boardAPI.getIndexPageArticleList, 4);
    const question = yield call(boardAPI.getIndexPageArticleList, 5);
    
    const res = {
      "notice": notice.data,
      "job": job.data,
      "free": free.data,
      "anonymous": anonymous.data.articles,
      "question": question.data
    }
    yield put({
      type: GET_NEW_POSTS_SUCCESS,
      payload: res
    });
  } catch (e) {
    yield put({
      type: GET_NEW_POSTS_ERROR,
      error: e.response
    })
  }
}
// BoardReducer

    ...
    case GET_NEW_POSTS:
      return {
        ...state,
        newPosts: {
          ...state.newPosts,
          loading: true
        }
      }
    case GET_NEW_POSTS_SUCCESS:
      return {
        ...state,
        newPosts: {
          notice: action.payload.notice,
          free: action.payload.free,
          job: action.payload.job,
          anonymous: action.payload.anonymous,
          question: action.payload.question,
          loading: false,
          error: null
        }
      }
    }

방식에 맞게 state를 수정할 필요도 있었다.

메인 페이지의 다른 컴포넌트에서 BoardData를 쓰는 경우는 없으니 최신게시물과 Board list용으로 newPosts로 묶어서 구분하였다.

const initialState = {
  ...
  hotPosts: {
    data: null,
    loading: false,
    error: null
  },
  newPosts: {
    notice: [],
    free: [],
    job: [],
    anonymous: [],
    question: [],
    loading: false,
    error: null
  },
  ...
}

새로운 액션을 만들었으니 액션을 dispatch하는 과정도 간소해졌다.

// IndexNewBoardContainer.js

useEffect(() => {
  dispatch(getNewPosts());
}, []);

상단의 최근게시물 컴포넌트에서 액션을 dispatch하므로, 하단부인 BoardList 에서는 dispatch할 필요가 없고, 업데이트되는 상태에 따라 값을 전달해주기만 하면 되었다.

// IndexBoardListContainer.js

const {notice, free, job, anonymous, question} = useSelector(state => state.boardReducer.newPosts);

useEffect(()=> {
  switch (selectedBoard) {
    case 0:
      return setArticles(notice);
    case 1:
      return setArticles(free);
    case 2:
      return setArticles(job);
    case 3:
      return setArticles(anonymous);
    case 4:
      return setArticles(question);
  }
},[selectedBoard, notice]);

이렇게 두 컴포넌트를 동시에 제작하면서 리듀서의 기능이 확실히 Vue의 Vuex와 비슷하다는 느낌이 들었다.

간편하게 형제컴포넌트에서 props를 사용하지 않고도 값 공유를 할 수 있었다. 이게 리듀서지..

State가 업데이트되었을 때 핸들링하는 방식 또한 이해하고 나니 간편하다고 생각이 들었다. 전체적으로 만족한다.

profile
FrontEnd Developer

0개의 댓글