12-4. 좋아요 / 좋아요 취소 API 함수 및 액션 작성

이제 좋아요 기능 구현을 위한 백엔드 작업은 끝났습니다. 프론트엔드 작업을 진행해볼까요?

API 함수 만들기

우선, 방금 만든 API 를 요청 할 수 있도록 API 함수를 만들어주겠습니다.

src/lib/api/posts.js

(...)

export const like = (postId) => axios.post(`/api/posts/${postId}/likes`);
export const unlike = (postId) => axios.delete(`/api/posts/${postId}/likes`);

기존의 posts.js 안에서, like 함수와 unlike 함수를 추가해주었습니다. 이 함수들은 postId 값을 파라미터로 받게됩니다.

액션 작성하기

이제 위 함수를 호출하는 액션들을 작성하겠습니다.

src/redux/modules/posts.js

(...)

const LIKE_POST = 'posts/LIKE_POST'; // 포스트 좋아요
const UNLIKE_POST = 'posts/UNLIKE_POST'; // 포스트 좋아요 취소

(...)

export const likePost = createAction(LIKE_POST, PostsAPI.like, (payload) => payload); // postId 를 meta 값으로 설정
export const unlikePost = createAction(UNLIKE_POST, PostsAPI.unlike, (payload) => payload); // postId 를 meta 값으로 설정

(...)

export default handleActions({
    (...)

    ...pender({
        type: LIKE_POST,
        onPending: (state, action) => {
            const index = state.get('data').findIndex(post=>post.get('_id') === action.meta);
            return state.updateIn(
                ['data', index], 
                (post)=> post.set('liked', true) // liked 값을 true 로 바꾸고
                             .update('likedCount', count => count + 1) // likedCount 값을 1 더함
            );
        },
        // 요청 끝나면 실 서버값으로 설정
        onSuccess: (state, action) => {
            const index = state.get('data').findIndex(post=>post.get('_id') === action.meta)
            return state.setIn(['data', index, 'likesCount'], action.payload.data.likesCount) 
        }
    }),
    ...pender({
        type: UNLIKE_POST,
        onPending: (state, action) => {
            const index = state.get('data').findIndex(post=>post.get('_id') === action.meta);
            return state.updateIn(
                ['data', index], 
                (post)=> post.set('liked', false) // liked 값을 false 로 바꾸고
                             .update('likedCount', count => count - 1) // likedCount 값을 1 뺌
            );
        },
        // 요청 끝나면 실 서버값으로 설정
        onSuccess: (state, action) => {
            const index = state.get('data').findIndex(post=>post.get('_id') === action.meta);
            return state.setIn(['data', index, 'likesCount'], action.payload.data.likesCount);
        }
    })

}, initialState);

이번에 만든 액션은, 기존의 데이터를 수정하기 때문에, 지금까지 해왔던것들과 처리방식이 조금 다릅니다. 우선, onPendingonSuccess 에서, API 함수를 호출 할때에 전달했던 파라미터인 postId 값을 참조 할 수 있도록, createAction 을 통하여 액션생성자를 만들 때 두번쨰 파라미터로 (payload) => payload 를 넣어주게됩니다. 두번쨰 파라미터는 metaCreator 값인데요, 여기에서는 payload 의 값에 따라서 액션 객체의 meta 값을 설정해줍니다. 지금의 경우엔 action.meta 값이 postId 가 됩니다. 나중에 이 meta 값을 참조하여 findIndex 함수를 통하여 몇번째 포스트를 수정해야 할 지 조회를 하여 포스트를 업데이트하게됩니다.

그리고, 이번 액션의 경우엔 opPending 에서도 작업을 진행하는데요, 어떤 작업이 진행이 되냐하면, 요청이 시작되면 일단 liked 값을 true 로 바꾸거나 false 로 바꿔줍니다. 좋아요 혹은 좋아요 취소 API 를 하게 될 때 0.x 초의 딜레이가 발생하게 됩니다. (로컬에서는 작업할때는 매우 빠르겠지만요) 그렇기 때문에, 좋아요를 하거나 좋아요 취소를 했을때 일정 딜레이 이후에 좋아요 버튼의 색상이 변경되는 현상이 발생하게 되는데, onPending 에서 미리 liked 값을 바꿔줌으로서, 더욱 자연스러운 유저 경험을 제공해줍니다.

그리고, onSuccess 부분에서는, 현재 likedCount 값으로 업데이트를 해줍니다.

results matching ""

    No results matching ""