함수를 실행해 함수의 내부의 값은 함수가 실행될 때마다 초기화 한다. 그 값을 가지기 위해서 데이터의 위치 값(ex., index, key등)을 closer를 통해 envirenment에 묶어 놓는다.
여기서 재미있게 사용할 수 있는게 “게으른 초기화”라는 부분인데, 변수에 대신 함수로 넘기면 작동이 된다. 이때는 맨 처음 초기화 단계에서만 실행이 되는데 그래서 함수를 한번 거치기 때문에, 복잡하거나 무거운 함수에서만 사용하는 것이 추천된다.(리엑트 공식문서 추천 방식) 코드는 아래처럼 쓰면 된다.
const [count, setCount] = useState(
Number.parseInt(window.localStorage.getItme(cacheKey)),
)
// 게으른 초기화
const [count, setCount] = useState(() =>
Number.parseInt(window.localStorage.getItem(cacheKey)),
)게으른 초기화를 사용하게 되면, Number.parseInt(window.localSorage.getItme(cacheKey)) 를 통해 접근하는 것이 아닌 일종의 cache된 값을 사용하게 되어 훨신 경제적으로 사용할 수 있게 한다.
사실상 react의 꽃 중 하나가 아닐까? 라고 생각이 된다. UI=F(x) 라는 뜻을 만들기 위해, 가장 처리해야하는 것은 부수적인 변경점들인데, 리엑트는 어떻게 이것을 해석했을까?의 답이 여기 있다라고 생각한다.
useEffect는 먼저 첫번째 인자를 부수효과가 포함된 함수를, 두번재 인자로는 의존성 배열을 전달한다. 그런데, 의존성 배열이 어떻게 변한지를 알고 실행할까? 위에서 말했다 싶이 현재의 react는 UI=F(x)를 기본적인 체제로 돌아간다. 즉 매번 UI를 그리기 위해서는 그 함수를 불러야 한다는 것이다. 자연스럽게 떠오르는 생각으로 그 함수가 부를 때 useEffect를 실행 시키면 되겠다가 따라온다.
함수형 컴포넌트에서 useEffect는 이름답게 부수 효과가 있는 함수 앞, 뒤에 실행하는 요소들이 있다. 그 중 부수 효과를 제거하는 곳은 어디일까? 흔히 clean up이라는 곳에서 이루어진다. 예를 들어, useEffect에서 어떤 함수가 변했을 때 어떤 이벤트 A를 등록했다고 치자. 그리고 새로운 UI가 그려지면, 그 이벤트는 2번 등록이 된다. 그러면 사용자는 어떠한 액션에 취했을때 데이터가 2번씩 간다는 것이다.😮 이게 얼마나 심한 것이냐면(정말 만약이다) 사용자가 버튼을 클릭할 때마다 자신이 원한 만큼의 기부를 할 수 있다고 치자. 코딩을 잘못해서 useEffect에 버튼의 action으로 event를 등록하면 어떻게 될까?(다시한번 말하지만 절대 저럴일 없다) 점차 그 기부하는 금액이 늘어날 것이다!! 그래서 clean up함수가 정말 중요하다.
사용하면서 주의해야 하는 점을 알려준다. 예를 들면, eslint-disable-line, react-hooks/exhausitive-deps의 주석은 피하자. useEffect의 첫 번째 인수에 함수명을 부여하자. 거대한 useEffect를 만들지 말자. 불필요한 외부 함수를 만들지 말자. 책에서 말하는 것들은 어느정도 동의는 되는데, 함수명 부여하는 것은 아직도 모르겠다.
추가적으로 비동기에 대한 이야기를 하는데, cleanup이 말하는 의미를 안다면 어떻게 다루어야 할지 알게 될 것이다. 그리고 이를 정말 쉽게 다룰 수 있도록 만들어준 tanstack-query에게 만세! 만세!
무거운 함수를 cache를 해주는 친구이다. 이거를 긱하게 사용한다면, useEffect처럼 연산 수행하는 타이밍을 만들 수 있어서 유용하게 사용할 수 있다.
useCallback은 그냥 useMemo의 함수 버전일 뿐이다. (javascript는 1급 객체를 지원하는 언어다) 그냥 다른 개발자들과의 혼돈을 주지 않게 하기 위한 요소일 뿐이다.
useRef도 useEffect만큼은 아니지만 다른 것들보다 react를 구성하는 중요한 것 중 하나라고 생각한다. 먼저 useState와의 차이점을 보자.
아니 이럴꺼면 왜 있는걸까? 밖에서 선언하면 되는것이 아닌가? → 이것에 대한 답은 UI=F(x)에 있다. 내 생각부터 이야기 하자면, react는 javascript조차(ex., DOM객체 등)react안에서 조작하고 싶다 라는 것이다. react는 내부적인 생명주기가 있다. 그리고 심지어 javascript의 엔진의 생명주기와도 다르다고 생각한다. 그리고 UI를 그리기 위한 모든 내용을 react는 가지고 싶어 한다. 그 useRef가 나온게 아닌가 생각된다.
react에서 단점으로 여러가지가 있는데, 그 중 하나가 props drilling이라는 이슈이다. UI=F(x)를 그리기 위해서 부모의 데이터를 자식에게 전달을 하는데, 그 깊이가 3중, 4중으로 가면 점차 넓어지고 힘들어진다. 그래서 이를 DI라는 형태로 해결하기 위해 여러 방법을 제시하는데(대표적으로 hooks, HoC등) 여기서는 context라는 방식을 제시해주었다.
const Context = createContext<{hello: string} | undefined>(undefined)
function ParentComponent() {
return (
<>
<Context.Provider value={{ hello:'react' }}>
<Context.Provider value={{ hello:'javascript' }}>
<ChildComponent />
</Context.Provider>
</Context.Provider>
</>
)
}
function ChildComponent() {
const value = useContext(Context)
// 여기서는 가장 가까운 Context인 javascript가 나온다.
return <>{value ? value.hello: ''}</>
}요즘에는 use라는 훅이 등장하면서 마법과 같은 훅으로 어디에서든 (심지어 후에 나오는 rools of hook조차도 무시하는) 사용할 수 있게 되었다.
사실 useState와 다른것이 있나? 라는 생각을 한다. 그저 여러 기준 점으로 여러개의 state가 상호작용을 하면서 데이터가 변경이 되면 useReducer를 선택하면 될 것이다.