기존에 진행했던 팬레터 웹 어플리케이션 프로젝트를 기반으로 새 프로젝트를 시작한다.
기존에 redux를 사용했던 부분을 전부 다 redux-toolkit으로 전환 할 것.
jwt 인증서버를 이용한 사용자 계정 관련된 제어를 할 것.(회원가입, 로그인, 유저 정보 수정, 회원 조회 등)
react-router-dom 의 Outlet 을 이용하여 화면을 구성할 것.
json-server 를 사용하여 팬레터 상태관리를 할 것.
서버 통신관련된 부분을 구현할때 Thunder Client를 적극 활용할 것.
오늘은 리덕스를 리덕스 툴킷으로 바꾸는 것을 해 보았는데 이에 대해 기록하고자 한다.
import { configureStore } from "@reduxjs/toolkit";
import memberReducer from "../modules/chosenMemberSlice";
import modalReducer from "../modules/modalControlSlice";
import fanLetterReducer from "../modules/fanLetterSlice";
const store = configureStore({
reducer: {
chosenMember: memberReducer,
modalControl: modalReducer,
fanLetter: fanLetterReducer,
},
middleware: (getDefaultMiddleware) =>
getDefaultMiddleware({
serializableCheck: false,
}),
});
export default store;
위 코드와 같이 store 설정을 해 주었다. createStore 대신 configureStore를 사용하였으며 각 slice들로부터 리듀서를 import 해오고 있다.
이때 slice에서 리듀서는 export default 했으므로 원하는 대로 이름을 붙일 수 있다. 나는 조금더 알아보기 쉽게 Reducer 라고 붙여주었다.
또한 reducer 내에서 왼쪽에 오는 key를 잘 설정해야 하는데 이것이 결국 컴포넌트 내에서 state를 불러올때 거기서 나타나는 이름이 되기 때문이다. 기존에 이미 redux 를 쓰던 프로젝트를 redux-toolkit으로 바꾸는 상황이기 때문에 원래 코드에서 state 이름으로 사용했던 이름을 그대로 적어줘야 코드를 대량으로 수정하는 상황을 피할 수 있다. modalControl 대신 modal 이라고 이름을 정하면 원래 코드에서 modalControl로 state를 읽어오는 모든 코드를 전부 다 수정해 줘야한다.
import dummyData from "fakeData.json";
import { createSlice } from "@reduxjs/toolkit";
const initialState = [...dummyData];
const fanLetterSlice = createSlice({
name: "fanLetter",
initialState,
reducers: {
setFanLetters: (state, action) => {
return [...action.payload];
},
},
});
export const { setFanLetters } = fanLetterSlice.actions;
export default fanLetterSlice.reducer;
예시로 fanLetterSlice 하나만 살펴보자.
createSlice를 이용하여 생성하게 되며 name, initialState, reducers를 설정해 주면 된다.
이때 reducers 객체의 key로 적은 것이 그대로 action creator 로 작동하게 되며 fanLetterSlice.actions
로 내보낼때도 이것을 내보내게 된다.
리덕스만 사용하였을때는 발생하지 않던 에러였는데 리덕스 툴킷을 적용한 이후에 발생한 에러이다. 검색해보니 이 에러 메세지는 Redux 상태에 직렬화 할 수 없는(non-serializable) 값이 있음을 나타내는 것으로, Redux는 상태에 함수나 DOM 노드와 같이 직렬화할 수 없는 값은 상태에 저장하고 있어서 발생하는 것이라고 한다.
에러의 발생 원인을 알고 나니 짐작이 가는 부분이 있다.
dispatch(
activateModal({
title: "수정 확인",
message: "이대로 수정하시겠습니까?",
btnMsg: "확인",
btnFn: onEditConfirm,
})
);
바로 이 부분인데, 커스텀 모달을 제어하기 위해 리덕스 상태로 객체를 만들어서 던지는 코드이다. 이때 객체의 value로 onEditConfirm 이나 onDelte 같은 함수를 만들어 사용하고 있었는데 이부분이 문제를 일으킨 것이다.
해결책으로 떠오른 것은 두가지가 있다. 하나는 만들어둔 커스텀 모달 컴포넌트를 폐기하고 대신 sweetalert2를 사용하는 것이다. sweetalert은 작동시킬때 리덕스 상태에 의존하지 않으므로 이 문제를 완전히 피해갈 수 있다.
다른 해결책은 미들웨어를 사용하는 것이다. 위에 적은 store 코드에서 확인할 수 있는 부분인데,
middleware: (getDefaultMiddleware) =>
getDefaultMiddleware({
serializableCheck: false,
}),
이 세줄의 코드를 reducer 다음에 추가해 줌으로써 에러 발생을 막을 수 있다. 직렬화 불가능한 것(이 경우엔 함수)를 리덕스 상태로 전달해서 뜨는 에러인데 직렬화 가능한지 체크하는 로직의 작동을 중간에 미들웨어를 이용하여 막아버리는 것이다.
form태그 사용할때 기본적으로 submit이 이루어지면 항상 새로고침이 되는 것을 e.preventDefault()
로 막아버리는 것과 유사한 느낌이다.
이번에는 미들웨어를 사용하는 해결책을 선택하기로 했다. 기껏 열심히 만들어둔 모달 컴포넌트를 사용하지 않는 것은 아쉬웠기 때문이다.
sweetalert 을 사용하지 않더라도 이번 프로젝트에 react-toastify
를 사용할 예정이기 때문에 서드파티 라이브러리를 사용해보는 경험은 충분히 할 수 있다.
출처)https://school.programmers.co.kr/learn/courses/30/lessons/147355
숫자로 이루어진 문자열 t와 p가 주어질 때, t에서 p와 길이가 같은 부분문자열 중에서, 이 부분문자열이 나타내는 수가 p가 나타내는 수보다 작거나 같은 것이 나오는 횟수를 return하는 함수 solution을 완성하세요.
예를 들어, t="3141592"이고 p="271" 인 경우, t의 길이가 3인 부분 문자열은 314, 141, 415, 159, 592입니다. 이 문자열이 나타내는 수 중 271보다 작거나 같은 수는 141, 159 2개 입니다.
function solution(t, p) {
let arr=[]
const tLength=t.length
const pLength=p.length
for(let i=0;i<=tLength-pLength;i++){
let num=t.split('').splice(i,pLength).join('');
arr.push(num)
}
let j=0
arr.forEach(el=>{if(el<=p){j++}})
return j
}
function solution(t, p) {
var answer = 0;
for(let i = 0; i < t.length; i++) {
const sub = t.substring(i, i + p.length);
if(sub.length === p.length && +sub <= +p) answer++;
}
return answer;
}
substring을 처음 알게 되었다.
내 풀이에서 split, splice, join을 체이닝 한 것을 substring 하나로 처리할 수 있다.
str.substring(x,y)
인자를 두개 받을 수 있으며 x인덱스부터 y인덱스 앞까지를 잘라서 반환한다.
str.substring(x)
인자를 하나만 전달한 경우 x인덱스를 포함하여 그 이후를 전부 반환한다.