diff --git "a/Chapter_3/GeonHo/1. \353\246\254\354\225\241\355\212\270\354\235\230 \353\252\250\353\223\240 \355\233\205 \355\214\214\355\227\244\354\271\230\352\270\260/3.1.3 useMemo.md" "b/Chapter_3/GeonHo/1. \353\246\254\354\225\241\355\212\270\354\235\230 \353\252\250\353\223\240 \355\233\205 \355\214\214\355\227\244\354\271\230\352\270\260/3.1.3 useMemo.md" new file mode 100644 index 0000000..338ff69 --- /dev/null +++ "b/Chapter_3/GeonHo/1. \353\246\254\354\225\241\355\212\270\354\235\230 \353\252\250\353\223\240 \355\233\205 \355\214\214\355\227\244\354\271\230\352\270\260/3.1.3 useMemo.md" @@ -0,0 +1,7 @@ +# 3.1.3 useMemo + +useMemo는 비용이 큰 연산에 대한 결과를 메모이제이션해 두고, 이 저장된 값을 반환하는 훅이다. + +의존성 배열의 값이 변경되지 않았으면 함수를 재실행하지 않고 이전에 기억해 둔 해당 값을 반환한다. + +단순히 값 뿐 아니라 컴포넌트도 메모가 가능하다 (물론 이 경우 React.memo 사용을 추천.) diff --git "a/Chapter_3/GeonHo/1. \353\246\254\354\225\241\355\212\270\354\235\230 \353\252\250\353\223\240 \355\233\205 \355\214\214\355\227\244\354\271\230\352\270\260/3.1.4 useCallback.md" "b/Chapter_3/GeonHo/1. \353\246\254\354\225\241\355\212\270\354\235\230 \353\252\250\353\223\240 \355\233\205 \355\214\214\355\227\244\354\271\230\352\270\260/3.1.4 useCallback.md" new file mode 100644 index 0000000..f1bfa0d --- /dev/null +++ "b/Chapter_3/GeonHo/1. \353\246\254\354\225\241\355\212\270\354\235\230 \353\252\250\353\223\240 \355\233\205 \355\214\214\355\227\244\354\271\230\352\270\260/3.1.4 useCallback.md" @@ -0,0 +1,8 @@ +# 3.1.4 useCallback + +useMemo 훅이 값을 기억하는 역할이었다면, useCallback은 인수로 넘겨받은 콜백 자체를 기억한다.
+즉, 특정 함수를 새로 만들지 않고 재사용한다는 의미이다. + +값의 메모이제이션을 위해 useMemo를 사용했다면, 함수의 메모이제이션을 위해 사용하는 것이 useCallback이다. + +해서 useMemo와 useCallback의 차이는 메모이제이션 대상이 변수냐 함수냐의 차이다. diff --git "a/Chapter_3/GeonHo/1. \353\246\254\354\225\241\355\212\270\354\235\230 \353\252\250\353\223\240 \355\233\205 \355\214\214\355\227\244\354\271\230\352\270\260/3.1.5 useRef.md" "b/Chapter_3/GeonHo/1. \353\246\254\354\225\241\355\212\270\354\235\230 \353\252\250\353\223\240 \355\233\205 \355\214\214\355\227\244\354\271\230\352\270\260/3.1.5 useRef.md" new file mode 100644 index 0000000..401f5c9 --- /dev/null +++ "b/Chapter_3/GeonHo/1. \353\246\254\354\225\241\355\212\270\354\235\230 \353\252\250\353\223\240 \355\233\205 \355\214\214\355\227\244\354\271\230\352\270\260/3.1.5 useRef.md" @@ -0,0 +1,98 @@ +# 3.1.5 useRef + +### useRef와 useState의 차이점 + +useRef는 useState처럼 렌더링이 일어나도 state를 저장한다는 공통점이 있지만, 명확한 차이점이 있다. + +- 반환값의 current로 접근 및 변경이 가능. +- 그 값이 변하더라도 렌더링이 발생되지 않는다. + +
+ +### useRef는 왜 필요할까 ? + +우선, 아래 코드를 살펴보자. + +```js +let value = 0; + +const Component = () => { + const handleClick = () => { + value += 1; + } + ... +} +``` + +위 코드는 몇가지 단점이 있다.
+ +- 컴포넌트가 아직 렌더링되지 않아도 value가 존재하며, 이는 메모리에 불필요한 값을 갖게한다. +- Component가 여러번 생성된다면, 각 Component는 모두 동일한 value를 가리키게 된다. + +useRef는 위 2가지 문제를 모두 극복할 수 있는 리액트식 접근법이다. + +
+ +useRef를 사용할 수 있는 유용한 경우는 렌더링을 발생시키지 않고 원하는 상태값을 저장할 수 있다는 특징이다.
+이를 활용하여 usePrevious()같은 훅을 구현할 수 있다. + +```jsx +function usePrevious(value) { + const ref = useRef(); // 최초 렌더링 시 undefined + + useEffect(() => { + ref.current = value; + }, [value]); + + return ref.current; +} + +function Component() { + const [counter, setCounter] = useState(0); + const prevCounter = usePrevious(counter); + + const handleClick = () => { + setCounter((prev) => prev + 1); + }; + + return ( + + ); +} + +/* + 결과 + 0 undefined + 1 0 + 2 1 + 3 2 +*/ +``` + +위 코드의 동작 원리에 대해 생각해보자.
+ +```jsx +const prevCounter = usePrevious(counter); +``` + +1. 위 코드가 실행되면 usePrevious 내부의 ref는 useRef에 의해 undefined를 할당받는다.
+2. useEffect 훅은 컴포넌트가 렌더링된 후에 실행된다. (이는 컴포넌트가 화면에 그려진 직후에 비동기적으로 실행되는 사이드 이펙트를 처리하기 위함.)
+3. undefined를 리턴하고 난 후, useEffect 내부 로직이 실행되어 ref.current 값을 업데이트한다. + +이렇듯 개발자가 원하는 시점에서 렌더링에 영향을 미치지 않고 보관해 두고 싶을때 유용하게 사용할 수 있다. + +
+ +### useRef는 어떻게 구현되어있을까? + +```jsx +// Preact 기준 +function useRef(initialValue) { + return useMemo(() => ({ current: initialValue }), []); +} +``` + +**위와 같이 렌더링이 되어도 변하지 않게끔 useMemo에 넣어두었다.**
+**배열에 값을 저장하고, 디펜던시 어레이에 아무것도 넣지 않아 각 렌더링마다 동일한 객체를 가리키게 될 것이다.** diff --git "a/Chapter_3/GeonHo/1. \353\246\254\354\225\241\355\212\270\354\235\230 \353\252\250\353\223\240 \355\233\205 \355\214\214\355\227\244\354\271\230\352\270\260/3.1.6 useContext.md" "b/Chapter_3/GeonHo/1. \353\246\254\354\225\241\355\212\270\354\235\230 \353\252\250\353\223\240 \355\233\205 \355\214\214\355\227\244\354\271\230\352\270\260/3.1.6 useContext.md" new file mode 100644 index 0000000..6296d8e --- /dev/null +++ "b/Chapter_3/GeonHo/1. \353\246\254\354\225\241\355\212\270\354\235\230 \353\252\250\353\223\240 \355\233\205 \355\214\214\355\227\244\354\271\230\352\270\260/3.1.6 useContext.md" @@ -0,0 +1,56 @@ +# useContext + +### useContext란? + +부모 / 자식 트리 관계를 가지는 리액트에서 자식에게 전달하려는 props 거리가 멀어질수록 props drilling 현상이 발생하게 된다. + +이런 현상을 극복하기 위해 등장한 개념이 `Context`이다. + +
+ +### Context 를 함수형 컴포넌트에서 사용할 수 있게 해주는 useContext 훅 + +```jsx +const Context = createContext<{ hello: string } | undefined>; + +function Parent() { + return ( + <> + + + + + + + ) +} + +function Child() { + const value = useContext(Context); + + return <>{value && value.hello} +} + +// 결과: 'JS', 'react'가 아니라 'JS'가 리턴된다. +``` + +
+ +### useContext를 사용할 때 주의할 점 + +useContext를 함수형 컴포넌트 내부에서 사용할 땐 컴포넌트 재활용이 어려워진다.
+useContext가 선언돼 있으면 Provider에 의존성을 가지기 때문이다. + +이를 위해 useContext를 사용하는 컴포넌트를 최대한 작게 하거나 재사용되지 않는 컴포넌트에서 사용하는 것을 고려할 수 있다.
+또한, 모든 context를 최상위 루트에 둘 수도 있지만, 이는 좋은 접근법은 아닌 듯 하다.
+ +마지막으로, context와 useContext를 상태관리에 사용하는 것이라 생각하는데, 그렇지 않다.
+엄밀히 말하자면 context는 상태를 주입해주는 API 이다.
+ +상태 관리 라이브러리가 되기 위해서는 최소한 다음 2가지 조건을 만족해야 한다. + +- 어떠한 상태를 기반으로 다른 상태를 만들어 낼 수 있어야 한다. +- 필요에 따라 이러한 상태 변화를 최적화 할 수 있어야 한다. + +context는 위 2가지 모두 못한다.
+context는 단순히 props 값을 하위로 전달해 줄 뿐.
diff --git "a/Chapter_3/GeonHo/1. \353\246\254\354\225\241\355\212\270\354\235\230 \353\252\250\353\223\240 \355\233\205 \355\214\214\355\227\244\354\271\230\352\270\260/3.1.7 useReducer.md" "b/Chapter_3/GeonHo/1. \353\246\254\354\225\241\355\212\270\354\235\230 \353\252\250\353\223\240 \355\233\205 \355\214\214\355\227\244\354\271\230\352\270\260/3.1.7 useReducer.md" new file mode 100644 index 0000000..61035e8 --- /dev/null +++ "b/Chapter_3/GeonHo/1. \353\246\254\354\225\241\355\212\270\354\235\230 \353\252\250\353\223\240 \355\233\205 \355\214\214\355\227\244\354\271\230\352\270\260/3.1.7 useReducer.md" @@ -0,0 +1,21 @@ +# useReducer + +useReducer는 useState의 심화버전으로 볼 수 있다. + +반환 값은 useState처럼 길이가 2인 배열이다. + +- state : 현 useReducer가 가진 값 +- dispatcher : setState와 달리 action(state를 변경할 수 있는 action)을 넘겨준다. + +인수는 2개에서 3개의 인수를 필요로 한다. + +- reducer : useReducer의 기본 action을 정의하는 함수다. +- initialState : useReducer의 초기값을 의미한다. +- init ?: 초기값을 지연해서 생성시키고 싶을 때 사용한다. + +useReducer가 조금 복잡해 보이지만, 목적은 간단하다.
+바로 복잡한 형태의 state를 사전에 정의된 dispatcher로만 수정할 수 있게 하는 것.
+ +state가 복잡하거나, 여러개의 단순한 state들을 묶어 관리하기도 한다. + +즉, useReducer나 useState나 결국 클로저를 활용해 값을 가둬서 state를 관리한다.