https://www.udemy.com/course/clean-code-react/
udemy의 '클린코드 리액트' 강의를 듣고 정리했습니다.
State
컴포넌트 상태, 전역 상태, 서버 상태와 이를 관리하기 위한 행동들이 있다.
상태란 사물, 현상이 놓여있는 모양이나 형편을 뜻하며, 예시로는 '무방비 상태', '건강상태', '기차가 끊긴 상태' 등등이 있다.
상태는 언제 바꾸는지, 최적화는 언제 해야 할지, 불변성은 왜 필요할지 등을 고민해봐야 한다.
올바른 초기 값 설정
초기 값
- 가장 먼저 렌더링 될 때 순간적으로 보일 수 있는 값
- 당연히 초기에 렌더링 되는 값.
초기값을 지키지 않을 경우
- 렌더링 이슈, 무한 루프, 타입 불일치로 의도치 않은 동작으로 런타임 에러가 생길 수 있다.
- 넣지 않으면 undefined
- 상태를 CRUD 할 때, 초기값을 잘 기억해 놔야 원상태로 돌아간다. ex) 초기 값이 문자열인데, 초기화를 숫자로 하는 등
초기값을 지켜야빈값, null처리를 할 때 불필요한 방어코드도 줄여준다
업데이트 되지 않는 값
const INFO = {name : ‘My Component’, value: ‘Clean Code React’}
위와 같이 업데이트되지 않는 변수를 리액트 컴포넌트에 직접적으로 가지고 있을 때, 이런 일반적인 객체를 props로 내리고 있는 경우는 좋지 못한 케이스이다.
- 컴포넌트 내부에 객체가 존재하기에, 렌더링 될 때마다 같은 값이더라도 다시 참조해서 트리거한다
- 계산, 기억 시기에 대한 로직이 존재하지 않는다. 불필요하게 참조하고 물고 있는 것
해결법
- 리액트 상태로 변경
- 컴포넌트 외부로 내보낸다.
업데이트되지 않는상수나 고유한 값들은 컴포넌트 외부에 관리되도록 내보내는 게 가장 좋다
플래그 상태로 바꾸기
플래그 값 : 프로그래밍에서 주로 특정 조건 혹은 제어를 위한 조건을 불리언으로 나타내는 값
isLogin의 조건이 매 렌더링마다 다시 계산되면서 isLogin에 들어가고, 아래에서 불리언 값이 판단되기 때문에 굳이 상태가 필요하지 않다. 즉 상태를 만들고, 상태를 위한 분기문을 칠 필요가 없다
플래그 상태의 경우 useState를 사용하지 않고 오른쪽 코드처럼 컴포넌트 내부의 변수를 활용할 수 있다.
useState 대신 플래그로 상태를 정의할 수 있다.
불필요한 상태
렌더링마다 고유의 값을 가질 수 있다는 가정을 한다면, 오른쪽 코드를 사용하는 것이 나을 수 있다. 오른쪽은 렌더링 될 때마다 고유의 complUserList가 생성되기에, 관리할 필요가 없고, set 할 필요도 없다
컴포넌트 내부의 변수는 렌더링 될 때마다 고유의 값을 가지는 계산된 값(computed value)이다. 따라서 useState가 아닌 const로 상태를 선언하는 게 더 좋은 경우도 존재함
useState 대신 useRef
리렌더링 방지가 필요하다면 useState 대신 useRef를 사용한다. useRef는 가변 컨테이너이다.
isMount처럼 특정 플래그 값 혹은 컴포넌트 내부에서 관리되지만 컴포넌트 내부에서 관리를 하기보다는 한 번 고정된 값을 컴포넌트에서 계속해서 사용하는 값, 이런 경우에는 useState가 필요 없다.
컴포넌트의 전체적인 수명과 동일하게 지속된 정보를 일관적으로 제공해야 하는 경우를 말한다.
오른쪽의 useRef는 렌더링을 유발하지 않는 가변 컨테이너이다. 즉 오른쪽 로직은 렌더링을 굳이 유발하지 않기 때문에, 불필요한 리렌더가 되지 않는다.
useState대신 useRef를 사용하면 컴포넌트의 생명주기와 동일한 리렌더링 되지 않는 상태를 만들 수 있다.
연관된 상태 단순화하기
‘복잡할수록 단순하게’라는 패턴을 KISS(Keep It Simple, Stupid)라고 한다. '단순하고 멍청하게 하는 것이 차라리 복잡한 것보다 낫다'라는 것이다.
비동기 데이터 통신이 끝난 다음, 맞는 렌더링을 하는 간단한 예제이다.
시도, 성공, 실패 3가지 케이스를 가진다. 현재는 문제없으나, 잠재적인 문제가 존재한다. isLoading이 true일 때는 나머지가 false일 것을 기대하는 등 loading, finish, error가 모두 다 연관이 되어있다. 그렇기에 실수할 가능성이 존재한다
이런 식으로 깔끔하게하나의 상태로만 관리를 할 수 있다. 객체를 사용하지 않기에 편안하게 문자열을 넣어주고 있다.
더 나아가 PROMISE_STATE를 선언해서 하드 하게 적은 코드를 대체할 수 있다. 단 하나의 상태에서 문자열만 사용해서 불변으로 상태를 관리하게 된다.
연관된 도미노와 같은 상태는 이런 식으로 묶어서 처리할 수 있는 방법이 있다. 또한 꼭 객체로만 묶을 필요 없이, 간단하게 문자열로 묶어서 관리할 수도 있다.
리액트의 상태를 만들 때 연관된 것들끼리 묶어서 처리하면 에러를 방지하고 코드가 간결해진다
연관된 상태 객체로 묶어내기
isLoading, isSuccess, isFaill은 모두 연관되어 있다. 리액트 상태를 만들 때, 객체로 연관된 것들끼리 묶어서 처리할 수 있다. 따라서 객체를 통해 오른쪽과 같이 설정할 수 있다.
한 가지 상태가 하나의 useState로 뽑힐 필요는 없다. 여러 상태도 하나의 useState로 표현할 수 있다.
*자바스크립트에서 객체 리터럴을 화살표 함수로 반환할 때, 중괄호({})를 객체 리터럴로 해석하는 것이 아니라, 함수 본문으로 해석한다. 그래서 중괄호 안의 객체 리터럴을 반환하기 위해서는 중괄호를 소괄호로 둘러싸야한다.
useState에서 useReducer로 리팩토링
구조화된 상태를 원한다면 useReducer를 사용할 수 있다. 여러 상태가 연관됐을 때, useState 대신 useReducer를 사용하면 상태를 구조화할 수 있다.
이전 상태 활용하기
겉보기에는 setAge(age + 1)의 방식이 문제없어 보이지만, setState는 비동기적 처리를 거칠 수 있기에, 이전 상태를 참고하는 것이 아니라, 갱신되기 전 상태를 계속 바라볼 수도 있다.
그렇기에 (prevAge) => prevAge + 1처럼 이전 상태를 가져와서 업데이트하는 방식으로 진행해야 예상할 수 있는 값을 뽑아낼 수 있다.
최대한 이전 state를 꺼내서 사용하는 방식으로 바꿔줘야 렌더링이나 특히 인풋을 핸들링하는 경우 불필요한 에러를 내지 않을 수 있다.
'프로그래밍 언어 > React 기초' 카테고리의 다른 글
리액트 현재 페이지 주소 복사! (0) | 2023.12.23 |
---|---|
리액트 API 호출 (0) | 2023.12.14 |
리액트 React Router (0) | 2023.12.03 |
리액트 간단한 모달창 만들기 (0) | 2023.11.29 |
리액트 드래그 앤 드롭(DND) (0) | 2023.11.27 |