The Ultimate React Course 2024: React, Redux & More 의 필기 위주로 작성되었습니다. 해당 강의는 강의 내용 기반으로 블로그 글 작성이 허용된 강의입니다.
React 내부에 "hook" 할수 있도록 해주는 특별한 내장 함수다. 아래 일들을 가능케 해준다:
보통 use로 시작하고, 우리만의 custom hook을 만들수도 있다.
보통 ESLint가 해당 룰들을 강제한다.
첫 규칙을 지켜야 하는 이유를 예시로 보자.
const [A, setA] = useState(23);
if(A === 23)
const [B, setB] = useState('');
useEffect(fnZ, []);
React의 fiber tree는 hooks의 리스트를 linked list 형태로 연결하는데, A가 최초에 23이어서 처음 그림처럼 linked list가 만들어지고, 이후 7이 되어 렌더 이후 사라진다면 linked list 자체가 파괴되어 버린다. Fiber tree는 렌더때마다 재생성되지 않기에, 리스트도 재생성되지 않는다.
이렇게 리액트가 linked list로 상태와 hooks를 관리하는 이유는 이렇게 해야 각 노드가 매 hook와 state를 고유하게 관리 가능하기 때문이다.
실제로 위의 룰을 어겨서 렌더때 hook 실행의 순서에 변경이 있거나, 실행되는 hook의 갯수에 변경이 있으면 프로그램이 바로 뻗어버린다.
ref, 즉 reference를 만들기 위한 hook다. 해당 hook는 렌더 간 그대로 유지되는, 변경 가능한 .current
속성을 가진 객체를 만들어준다. 그래서 위 사진처럼 23으로 초기화 하고, current 속성으로 값을 변경/접근 가능하다.
useRef는 렌더간 유지되어야 하는 변수 생성과, DOM 원소 선택과 저장에 사용된다. 보통 눈에 보이지 않는 데이터들을 위해 사용한다. 렌더 로직에는 state처럼 .current를 읽거나 쓰면 안된다.
stated와의 몇가지 차이다. ref는 렌더간 유지된다는 점 외에는 모두 state와 다른 성질을 가진다. state는 재렌더링을 트리거하지만 ref는 하지 않기에, 재렌더링을 원하지 않는경우 사용하면 좋다.
useState는 아래 상황에선 쓰기 빡셀 수 있다:
useReducer가 이를 해결할 수 있다. 복잡한 state와 관련된 state를 관리할 떄 편리하다. 보통 아래의 형식으로 초기화된다.
const [state, dispatch] = useReducer(reducer, initialState);
상태는 state에 저장되고, reducer는 state를 업데이트하는데 쓰이는 모든 로직을 포함하는 함수며, 이는 state 로직을 컴포넌트에서 분리한다. 강의에서는 "setState with superpowers" 정도로 묘사하는데, 적절한것 같다.
Reducer는 pure한 함수고, state와 action을 인자로 받아 다음 state를 반환한다. action은 state를 업데이트 하는 방법을 알려주는 객체다. 최종적으로 dispatch 함수를 setState함수처럼 사용해 reducer로 action을 보내서 state update를 트리거한다. 최종적으로 re-render가 트리거된다.
사용법은 아래 예시와 같다:
const [state, dispatch] = useReducer(reducer, initialState);
const dec = function () {
dispatch({ type: "dec" });
};
const inc = function () {
dispatch({ type: "inc" });
};
function reducer(state, action) {
console.log(state, action);
switch (action.type) {
case "dec":
return { ...state, count: state.count - state.step };
case "inc":
return { ...state, count: state.count + state.step };
}
...
}
위처럼 reducer가 action과 현재 state에 기반하여 새로운 값을 상태에 할당 할 수 있다.
큰 틀로 볼때, 주체인 dispatcher가 reducer에게 action을 dispatch하고, reducer는 안내대로 action을 실행하여 state를 업데이트해준다.
UI를 재사용해야 하면 컴포넌트를 사용하듯, 로직을 재사용해야 하면 custom hook을 쓸 수 있다. 만약 로직이 hooks를 포함하면 사용하면 되고, hooks가 없다면 일반 함수를 쓰면 된다.