Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
# 3.1.3 useMemo

useMemo는 비용이 큰 연산에 대한 결과를 메모이제이션해 두고, 이 저장된 값을 반환하는 훅이다.

의존성 배열의 값이 변경되지 않았으면 함수를 재실행하지 않고 이전에 기억해 둔 해당 값을 반환한다.

단순히 값 뿐 아니라 컴포넌트도 메모가 가능하다 (물론 이 경우 React.memo 사용을 추천.)
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
# 3.1.4 useCallback

useMemo 훅이 값을 기억하는 역할이었다면, useCallback은 인수로 넘겨받은 콜백 자체를 기억한다.<br>
즉, 특정 함수를 새로 만들지 않고 재사용한다는 의미이다.

값의 메모이제이션을 위해 useMemo를 사용했다면, 함수의 메모이제이션을 위해 사용하는 것이 useCallback이다.

해서 useMemo와 useCallback의 차이는 메모이제이션 대상이 변수냐 함수냐의 차이다.
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
# 3.1.5 useRef

### useRef와 useState의 차이점

useRef는 useState처럼 렌더링이 일어나도 state를 저장한다는 공통점이 있지만, 명확한 차이점이 있다.

- 반환값의 current로 접근 및 변경이 가능.
- 그 값이 변하더라도 렌더링이 발생되지 않는다.

<br>

### useRef는 왜 필요할까 ?

우선, 아래 코드를 살펴보자.

```js
let value = 0;

const Component = () => {
const handleClick = () => {
value += 1;
}
...
}
```

위 코드는 몇가지 단점이 있다. <br>

- 컴포넌트가 아직 렌더링되지 않아도 value가 존재하며, 이는 메모리에 불필요한 값을 갖게한다.
- Component가 여러번 생성된다면, 각 Component는 모두 동일한 value를 가리키게 된다.

useRef는 위 2가지 문제를 모두 극복할 수 있는 리액트식 접근법이다.

<br>

useRef를 사용할 수 있는 유용한 경우는 렌더링을 발생시키지 않고 원하는 상태값을 저장할 수 있다는 특징이다.<br>
이를 활용하여 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 (
<button onClick={handleClick}>
{counter} {prevCounter}
</button>
);
}

/*
결과
0 undefined
1 0
2 1
3 2
*/
```

위 코드의 동작 원리에 대해 생각해보자. <br>

```jsx
const prevCounter = usePrevious(counter);
```

1. 위 코드가 실행되면 usePrevious 내부의 ref는 useRef에 의해 undefined를 할당받는다.<br>
2. useEffect 훅은 컴포넌트가 렌더링된 후에 실행된다. (이는 컴포넌트가 화면에 그려진 직후에 비동기적으로 실행되는 사이드 이펙트를 처리하기 위함.) <br>
3. undefined를 리턴하고 난 후, useEffect 내부 로직이 실행되어 ref.current 값을 업데이트한다.

이렇듯 개발자가 원하는 시점에서 렌더링에 영향을 미치지 않고 보관해 두고 싶을때 유용하게 사용할 수 있다.

<br>

### useRef는 어떻게 구현되어있을까?

```jsx
// Preact 기준
function useRef(initialValue) {
return useMemo(() => ({ current: initialValue }), []);
}
```

**위와 같이 렌더링이 되어도 변하지 않게끔 useMemo에 넣어두었다.** <br>
**배열에 값을 저장하고, 디펜던시 어레이에 아무것도 넣지 않아 각 렌더링마다 동일한 객체를 가리키게 될 것이다.**
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
# useContext

### useContext란?

부모 / 자식 트리 관계를 가지는 리액트에서 자식에게 전달하려는 props 거리가 멀어질수록 props drilling 현상이 발생하게 된다.

이런 현상을 극복하기 위해 등장한 개념이 `Context`이다.

<br>

### Context 를 함수형 컴포넌트에서 사용할 수 있게 해주는 useContext 훅

```jsx
const Context = createContext<{ hello: string } | undefined>;

function Parent() {
return (
<>
<Context.Provider value={{ hello: 'react' }}>
<Context.Provider value={{ hello: 'JS' }}>
<Child />
</Context.Provider>
</Context.Provider>
</>
)
}

function Child() {
const value = useContext(Context);

return <>{value && value.hello}</>
}

// 결과: 'JS', 'react'가 아니라 'JS'가 리턴된다.
```

<br>

### useContext를 사용할 때 주의할 점

useContext를 함수형 컴포넌트 내부에서 사용할 땐 컴포넌트 재활용이 어려워진다.<br>
useContext가 선언돼 있으면 Provider에 의존성을 가지기 때문이다.

이를 위해 useContext를 사용하는 컴포넌트를 최대한 작게 하거나 재사용되지 않는 컴포넌트에서 사용하는 것을 고려할 수 있다.<br>
또한, 모든 context를 최상위 루트에 둘 수도 있지만, 이는 좋은 접근법은 아닌 듯 하다.<br>

마지막으로, context와 useContext를 상태관리에 사용하는 것이라 생각하는데, 그렇지 않다.<br>
엄밀히 말하자면 context는 상태를 주입해주는 API 이다.<br>

상태 관리 라이브러리가 되기 위해서는 최소한 다음 2가지 조건을 만족해야 한다.

- 어떠한 상태를 기반으로 다른 상태를 만들어 낼 수 있어야 한다.
- 필요에 따라 이러한 상태 변화를 최적화 할 수 있어야 한다.

context는 위 2가지 모두 못한다.<br>
context는 단순히 props 값을 하위로 전달해 줄 뿐.<br>
Original file line number Diff line number Diff line change
@@ -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가 조금 복잡해 보이지만, 목적은 간단하다. <br>
바로 복잡한 형태의 state를 사전에 정의된 dispatcher로만 수정할 수 있게 하는 것. <br>

state가 복잡하거나, 여러개의 단순한 state들을 묶어 관리하기도 한다.

즉, useReducer나 useState나 결국 클로저를 활용해 값을 가둬서 state를 관리한다.