분실물 페이지 제작 이후 메인 페이지의 컴포넌트들을 개발하였다.
이것이 코인 메인 페이지...!
대부분의 컴포넌트에서 리덕스를 사용해 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가 업데이트되었을 때 핸들링하는 방식 또한 이해하고 나니 간편하다고 생각이 들었다. 전체적으로 만족한다.