상태란?: Component 내부에서 관리되며 렌더링에 영향을 미치는 Javascript 객체입니다.
(변화하는 데이터로 이해해도 좋고, 화면에 영향을 끼치는 Javascript 객체로 봐도 됩니다.)
상태는 규모가 커질수록 복잡해지고 점점 얽히게 됩니다. 서로 다른 component 간 상태는 같아야하고, 출처도 같아야 합니다. A라는 사람의 인스타그램 팔로워 수가 100명이라면 B, C 모두에게 팔로워 수가 100으로 보여져야 합니다. B에게는 50, C에게는 150으로 보여지면 않됩니다.
따라서 상태는 일관성, 무결성을 유지해야 합니다.
예를 들면 쇼핑몰에서 같은 물건을 2개 이상 구매할 때, 기본값 1에서 +를 누르면 2가 됩니다. 이때 상태는 1에서 2로 변경 된 것입니다.
또 다른 예시로 인스타그램에서 누군가를 팔로우 했을 때, 그 누군가는 팔로워가 1 증가합니다. 이런 것 모두가 상태고, 상태 변화입니다.
상태는 전역 상태 / component 간 상태 / 지역 상태 세 가지로 나눌 수 있습니다.
전역 상태: 프로젝트 전체에 영향을 끼치는 상태입니다.
component 간 상태: 여러 component에서 관리되는 상태를 나타냅니다.
(다수의 component에서 쓰이고, 영향을 미칩니다. 프로젝트 곳곳에서 쓰이는 Modal을 예로 들 수 있습니다.)
지역 상태: 특정 component 안에서만 관리되는 상태를 말합니다. 다른 component와 상태를 공유하지 않고, input, selectBox 등이 있습니다.
상태를 관리하는 툴은 다양합니다. Context API, Redux, React Query, Recoil 등
- 불필요한 코드는 제거합니다. (우선 import 된 파일 중 불필요한 파일을 제거하고 사용하지 않는 파일 들이 있는지 확인 후 제거합니다.)
- 불필요한 과정을 제거합니다. 함수를 사용할 때, 불필요한 과정이 있는지 분석 후 불필요한 코드는 제거하거나 개선하는 것이 좋습니다. (이런 이유로 시간 복잡도를 따집니다.)
- 반복문 사용에 주의합니다. 원하는 결과값을 얻으면 break;를 통해 멈추는 것이 좋습니다. 원하는 결과값을 얻은 후 계속 된 반복문은 성능 저하를 발생시킵니다.
- 메모리 관리하기, Javascript 코드를 typeScript로 변경해 type을 설정해 성능을 향상 시킬 수 있습니다. typescript가 java type보다 불리한 이유는 java type이 더 구체적이기 때문입니다. int, float와 같이 number를 세분화 한다거나 등등..
- 단형 사용과 변수 설정, let, const에 대한 차이를 이해하고 고정된 값은 const를 사용하는 것이 좋습니다. const를 사용해도 문제가 없는 상황에서 let을 사용하는 경우 다형으로 인해 속도 저하를 발생시킵니다.
- 불필요한 데이터를 delete 보다 undefined 처리하는 것이 좋습니다. 객체에서 항목을 제거할 때 delete는 객체를 느리게 생성하는 원인입니다. 따라서 삭제하기 보다 속성을 undefined로 설정해 속도를 개선할 수 있습니다.
- Code Splitting 하기, 속도 개선을 할 수 있는 가장 좋은 방법 중 하나입니다. 큰 번들 하나를 import 하기 보다, 최소 코드가 실행될 수 있도록 작은 번들 여러개를 import하는 것이 좋습니다.
function multiply(x, y) {
return x * y;
}
// 무조건 x = 2, y = 3 이어야 하는 상황
let x = 2; y = 3;
multiply(x, y);
// const를 활용해도 상관없지만 let을 사용했다.
const x = 2; y = 3;
multiply(x, y);
// 하지만 무조건 2, 3 상황에서 변수 설정이 과연 필요할까?
multiply(2, 3);
// 바로 적어주면 단형이고 다형이고 상관없이 가장 빠르게 작동시킬 수 있다.
상태 관리 Library는 다양하지만, Redux 사용이 가장 많기 때문에, Redux를 사용하는 것이 좋고, Redux를 만든 곳에서 이제는 Redux-Toolkit을 권장하고 있기 때문에 Redux-Toolkit을 사용하는 것이 좋습니다.
Redux-Toolkit은 Redux 보다 코드를 간단하게 작성할 수 있고, 효율적으로 사용이 가능해집니다.
Toolkit 사용의 이점으로는 코드 개선, 유지 관리가 용이합니다.
1. 기존 Redux와 달리, Toolkit은 store 구성이 간단합니다.
2. Redux에서 작업할 때 많은 패키지를 추가해야 합니다. (Toolkit은 이미 포함)
3. Redux에서 너무 많은 코드를 필요로 합니다. (Toolkit은 상대적으로 간단하게 작성 가능합니다.)
아래는 Reudx 코드입니다. Reudx-Toolkit과 비교했을 때 상대적으로 길다는 걸 알 수 있습니다.
const todoReducer = (
state: TodoState = initialState,
action: TodoAction,
): TodoState => {
let newTodos = state.todos;
switch (action.type) {
case TodoActionType.tapAdd:
newTodos.push(action.payload.todo);
return {
...state,
todos: newTodos,
isModalVisible: false,
};
case TodoActionType.tapDelete:
newTodos.splice(action.payload.selectedIndex, 1);
return {
...state,
todos: newTodos,
};
case TodoActionType.tapUpdate:
newTodos[action.payload.selectedIndex] = action.payload.todo;
return {
...state,
todos: newTodos,
selectedIndex: action.payload.selectedIndex,
isModalVisible: false,
};
case TodoActionType.modalClose:
return {
...state,
isModalVisible: false,
selectedIndex: -1,
};
case TodoActionType.modalOpen:
return {
...state,
isModalVisible: true,
selectedIndex: action.payload.selectedIndex,
};
default:
return state;
}
};
아래는 Redux-Toolkit 코드입니다. 위 Redux와 비교했을 때 상대적으로 길다는 걸 알 수 있습니다.
export const todoSlice = createSlice({
name: 'todoList',
initialState,
reducers: {
add: (state, action: PayloadAction<TodoPayload>) => {
let newTodos = state.todos;
newTodos.push(action.payload.todo!);
state.todos = newTodos;
state.isModalVisible = false;
},
delete: (state, action: PayloadAction<TodoPayload>) => {
let newTodos = state.todos;
newTodos.splice(action.payload.selectedIndex!, 1);
state.todos = newTodos;
},
edit: (state, action: PayloadAction<TodoPayload>) => {
state.todos[action.payload.selectedIndex!] = action.payload.todo!;
state.isModalVisible = false;
},
modalOpen: (state, action: PayloadAction<TodoPayload>) => {
state.isModalVisible = true;
state.selectedIndex = action.payload.selectedIndex!;
},
modalClose: state => {
state.isModalVisible = false;
state.selectedIndex = -1;
},
},
});