1. FLUX란
2. 리덕스란
3. React에서 state 불변성
4. 리듀서 내부의 불변성과 ...연산자의 단점 해결 방법
5. side effect 문제점
1. FLUX 란 ⭐️⭐️
- FLUX는 라이브러리나 프레임워크가 아닌 추상적인 개념임
- MVC 패턴에서 쌍방향적인 데이터 흐름을 강조했던 것과 달리 FLUX 패턴에서는 단방향 데이터 흐름을 강조함
- MVC 패턴
- 사용자의 어떠한 행위(액션)가 있을 때, 이를 바탕으로 설계된 컨트롤러를 통해 모델을 변화하고 이를 뷰에 반영함
- 보여져야 할 뷰가 적거나, 변경될 모델이 많지 않다면 매우 효율적인 구조임
- 하지만, 모델과 뷰가 복잡하게 얽혀 있다면 어떤 모델이 변화되어 뷰가 변경되었는지 제대로 확인할 수 없는 경우가 생김
- FLUX 패턴
- MVC 패턴의 단점을 해결하기 위해 나온 단방향 데이터 흐름을 제어하는 패턴
- 단방형적 데이터 흐름 구조를 통해 어떤 액션이 디스패처에 의해 어떤 결과를 낳고 변화되는지 명확히 파악하고 알아볼 수 있음
- 사용자의 행위(액션)은 디스패처에 의해 통제됨
- 디스패처가 스토어를 업데이트하고 변경된 스토어에 대한 뷰를 리렌더링함
- 뷰에서는 스토어에 직접 접근하지 않으며, 디스패처로 다시 액션을 보내고 스토어를 업데이트한 뒤, 다시 뷰를 리렌더링
2. 리덕스란 ⭐️⭐️
- 리덕스(Redux)
- 상태 관리 라이브러리 중 하나로 여러 가지 상태 관리 라이브러리 중 가장 많이 사용됨
- Store(스토어)라는 변수를 이용해 전역 상태 관리를 하게 됨
- 전역으로 상태를 관리하기 때문에 props <-> state를 통해 부모 컴포넌트에서 자식 컴포넌트로, 자식의 자식 컴포넌트로 내려주지 않아도 사용할 수 있음
- 리덕스의 기본 원칙
- 응용 프로그램의 전역 상태는 단일 저장소 내의 트리에 저장됨
- 상태(state)는 읽기 전용임
- 순수 함수(부수 효과를 일으키지 않는 함수)에 의해서 변경되어야 함
3. React에서 state의 불변성 유지 ⭐️
- 객체는 실제 데이터 값이 아닌 참조 값을 가짐
- 따라서 복사하여 동일한 참조 값을 가지는 객체 중 하나라도 변경된다면, 모든 객체의 내부 값이 변경될 것임
- `...(spread) 연산자`를 통해 복사할 경우 A와 B는 같은 값을 가지더라도 새로운 객체를 할당 받은 상태됨
- 따라서 A와 B 내부의 값은 같더라도(같아 보이더라도) 참조하는 객체가 다르기 때문에 무결성을 유지할 수 있음
- 이미 복사를 한 프린트물은 A 인쇄물에 낙서를 하더라도 B 인쇄물에 영향을 미치지 않는 것과 같음
- 리액트에서는 데이터를 저장할 때 객체 형식 또는 배열 형식의 데이터를 많이 다루게 되는데, 원본 배열이 변경되는 경우 의도한 동작과 다르게 동작할 수 있으며, 어떤 함수에 의해 부수 효과(side effect)가 발생했는지 찾기 어려울 수 있음
4. 리듀서 내부에서 불변성 & 전개(spread) 연산자의 단점 해결 방법 ⭐️
- 컴포넌트는 다음과 같은 총 네 가지 경우에 업데이트함
- props가 바뀔 때
- state가 바뀔 때
- 부모 컴포넌트가 리렌더링될 때
- this.forceUpdate로 강제로 렌더링을 트리거할 때
- 리듀서의 initial state에는 서버에서 넘겨받는 정보를 저장하고 전역으로 해당 객체를 사용할 수 있는 저장소 역할을 함
- Q) 리듀서 내부에서 불변성을 지키는 이유?
- A) 불변성을 지킴으로써 각각의 고유한 참조값을 가지는 객체를 복사해서 사용함으로써 어떤 함수가 호출됐을 때 같은 객체를 참조한다면 생길 수 있는 불필요한 리렌더링과 부수효과를 줄일 수 있음
- 하지만 `...(spread) 연산자`를 사용하여 객체를 복사해 사용할 경우 객체의 깊이에 따라, 로직 구성이 매우 어려울 수 있음
- Q) `...(spread) 연산자`의 단점 해결 방법은?
- A) immer 라이브러리 사용, produce, drafe 라는 키워드를 사용해 기본의 `...(spread) 연산자`를 사용하지 않고도 불변성을 유지해주며 불필요한 부수효과(side effect)를 막아줌
/* 기존의 ...(spread)연산자 사용 */
const nextState = {
...state,
posts: state.posts.map((post) =>
post.id === 1
? {
...post,
comments: post.comments.concat({
id: 3,
text: '새로운 댓글',
}),
}
: post
),
};
/* immer 라이브러리 사용 */
const nextState = produce(state, (draft) => {
const post = draft.posts.find((post) => post.id === 1);
post.comments.push({
id: 3,
text: '와 정말 쉽다!',
});
});
5. 리액트 사용시 부수효과(side effect)로 인해 생기는 문제점 ⭐️⭐️
- 부수효과
- 함수가 만들어진 목적과는 다른 효과 또는 부작용
- 부수효과를 일으키는 함수(불순함수)
/* 코드 참조 (https://maxkim-j.github.io/posts/js-pure-function) */
// http 요청을 보내는 함수 : 순수함수 될 수 없음
const getData = () => {
axios.get('http://data.url')
.then(...)
.catch(...)
}
// 입력 내포한 함수 : 순수함수 될 수 없음
const typeInput = () => {
const input = prompt("Message");
return input;
}
// 파라미터를 직접 변경하는 함수 : 순수함수 될 수 없음
const changeParams = (arr, elem) => {
arr.push(elem);
return arr;
}
- 부수효과를 일으키지 않는 함수(순수 함수)
/* 코드 참조 (https://maxkim-j.github.io/posts/js-pure-function) */
const num_arr = [1, 2, 3, 4, 5];
// 매개변수의 값을 직접 변경하는 불순함수
const addSixImpure = (arr) => {
// 매개변수에 직접 6 추가
arr.push(6);
return arr;
};
// 매개변수를 복사한 값을 변경하는 순수함수
const addSixPure = (arr) => {
// 펼침 연산자로 새로운 배열에 6 추가
newArr = [...arr, 6];
return newArr;
};
// 매개변수 arr에 6이 있는지 확인하는 함수
const hasSix = (arr) => {
if (arr.includes(6)) {
return true;
} else {
return false;
}
};
const new_arr = addSixImpure(num_arr);
console.log(hasSix(num_arr)); // true
- addSixPure()과addSixInpure()는 언뜻 보면 별 차이가 없어 보이지만 addSixInpure()는 매개변수의 값을 직접 변경하는 불순함수이고, addSixPure()는 매개변수 값을 복사해서 변경하는 순수함수임
- addSixInpure()는 num_arr을 직접 바꿨기 때문에 함수가 실행되면 num_arr의 값이 [1,2,3,4,5,6]으로 영구히 바뀜. 그래서 hasSix()함수의 결과로는 true를 반환하게 되는 것
- 하지만 개발자의 의도가 변수 new_arr에 addSix 함수를 호출한 새로운 배열을 할당하고 난 후, 값이 [1,2,3,4,5]인 num_arr에 대해서 6이 있는지 판단하고 싶었던 거였다면 코드는 의도대로 실행되지 않았음
- addSixInpure()는 num_arr을 직접 바꿨기 때문에 함수가 실행되면 num_arr의 값이 [1,2,3,4,5,6]으로 영구히 바뀜. 그래서 hasSix()함수의 결과로는 true를 반환하게 되는 것
- 요약!
- react state는 직접 조작을 피하는 방식으로 부수효과를 방지함(state, props가 변경될 때 리렌더링이 되기 때문에 의도치 않게 부수효과를 가진 함수들로 인해 불필요한 리렌더링이 잦아질 수 있음)
- Redux의 reducer는 순수함수여야만 하는데, store값을 변경하는 함수가 부수효과를 동반하지 않아야 store 내부의 값들이 안전하게 보호될 수 있기 때문
'Frontend 📚 > React' 카테고리의 다른 글
[React] 리액트 기술 면접 핸드북 IV - 컴포넌트 라이프 사이클, Hooks etc. (0) | 2024.07.04 |
---|---|
[React] 리액트 기술 면접 핸드북 II - 함수 컨포넌트, props, state etc. (0) | 2024.06.27 |
[React] 리액트 기술 면접 핸드북 I - virtual DOM, react fiber etc. (0) | 2024.06.27 |
물품대여 서비스 개인프로젝트 (0) | 2024.06.19 |
[코딩애플] 쇼핑몰 프로젝트 Part11 - PWA 셋팅 (0) | 2023.11.01 |