Skip to content

SeonHyungJo/react-hook-sample

Repository files navigation

react-hook-sample

Contents

Basic Hooks

1. useState

const [state, setState] = useState(initialState);

첫번째 인자둜 μ΄ˆκΈ°κ°’ 을 λ„£μ–΄μ€€λ‹€. useState λŠ” μš°λ¦¬κ°€ 많이 μ‚¬μš©ν•˜λ˜ state μ΄ˆκΈ°ν™” μž‘μ—…κ³Ό λ™μΌν•˜λ‹€κ³  μƒκ°ν•˜λ©΄ 쉽닀. μƒμ„±μ‹œ μš°λ¦¬λŠ” 배열을 λ°›μ•„ 올 수 μžˆλ‹€.

λͺ¨λ“  Hook은 2개의 인자λ₯Ό λ°°μ—΄λ‘œ λ°›μ•„μ˜¨λ‹€.(λ“œλ¬Όκ²Œ μ•„λ‹Œ 것도 μžˆλ‹€.)

λ°°μ—΄μ˜ μ²«λ²ˆμ§ΈλŠ” μš°λ¦¬κ°€ λ„˜κ²¨μ£Όμ—ˆλ˜ μ΄ˆκΈ°ν™” 값이 λ“€μ–΄μ˜€κ³  μ΄ν›„μ—λŠ” λ³€κ²½λœ 값이 λ„˜μ–΄μ˜€κ²Œ λœλ‹€. λ‘λ²ˆμ§ΈλŠ” κ°’λ₯Ό λ³€κ²½ν•˜λŠ” ν•¨μˆ˜λ‹€.

re-renderκ°€ 될 경우 useState에 μ˜ν•΄ λ°˜ν™˜λœ 첫 번째 값은 항상 μ—…λ°μ΄νŠΈλ₯Ό μ μš©ν•œ ν›„ κ°€μž₯ 졜근 μƒνƒœκ°€ λœλ‹€.


1.1 Functional updates

μ—­μ‹œλ‚˜ μš°λ¦¬λŠ” 인자둜 ν•¨μˆ˜λ₯Ό λ³΄λ‚Όμˆ˜ μžˆλ‹€. κ·ΈλŸ¬λ‚˜ 기쑴에 μš°λ¦¬κ°€ μ‚¬μš©ν•˜λ˜ setState λ©”μ†Œλ“œμ™€λŠ” λ‹¬λΌμ„œ μžλ™μœΌλ‘œ 병합을 μ‹œμΌœμ£Όμ§€ μ•ŠλŠ”λ‹€.

즉 μš°λ¦¬κ°€ λ§Œλ“€λ•Œ λ§ˆλ‹€ ν•„μš”μ— 따라 병합을 ν•΄μ€˜μ•Όν•œλ‹€.

setState(prevState => {
  // Object.assign would also work
  return {...prevState, ...updatedValues}; // κ°„λ‹¨ν•˜κ²Œ spreadλ₯Ό μ‚¬μš©ν•΄μ„œ μƒˆλ‘œ 생성
});

1.2 Lazy initial state

initial state 에 μ—­μ‹œ ν•¨μˆ˜λ₯Ό μ‚¬μš©ν•  수 μžˆλ‹€. λ¦¬μ•‘νŠΈ μ‚¬μ΄νŠΈμ—μ„œ ν‘œν˜„μœΌλ‘œλŠ” κ°’ λΉ„μ‹Ό 계산 이라면 ν•¨μˆ˜λ₯Ό μ‚¬μš©ν•΄μ„œ ν‘œν˜„ν•˜λΌκ³  ν•œλ‹€.

const [state, setState] = useState(() => {
  const initialState = someExpensiveComputation(props);
  return initialState;
});

1.3 Bailing out of a state update

같은 값을 λ‹€μ‹œ μ—…λ°μ΄νŠΈλ₯Ό ν•˜λ”λΌλ„ λ¦¬μ•‘νŠΈμ—μ„œλŠ” μžμ‹μ„ re-render ν•˜κ±°λ‚˜ effect λ₯Ό λ°œμƒμ‹œν‚€μ§€ μ•ŠλŠ”λ‹€.(Object.isλ₯Ό μ‚¬μš©ν•΄μ„œ λΉ„κ΅ν–ˆλ‹€κ³  함_읽으면 μœ μš©ν•¨)


2. useEffect()

useEffect(() => {
  // Update the document title using the browser API
  document.title = `You clicked ${count} times`;
});

기본적으둜 λͺ¨λ“  λ Œλ”λ§μ΄ μ™„λ£Œλœ 후에 싀행이 λœλ‹€.

μ–΄λ–€ value κ°€ λ°”λ€Œμ—ˆμ„λ•Œ μ‹€ν–‰λ˜λ„λ‘ ν•  수 μžˆλ‹€.(λ‚΄κ°€ 바라보고 싢은 인자λ₯Ό 넣을 수 μžˆλ‹€.)


2.1 Cleaning up an effect

화면을 λ– λ‚˜κΈ° 전에 정리λ₯Ό ν• λ•Œ μ‚¬μš©ν•  수 μžˆλ‹€.(dispose()와 같은 λŠλ‚Œμž„)

μ•„λž˜μ˜ μ˜ˆμ‹œλ₯Ό 보게 되면 return으둜 λ§Œλ“  ν•¨μˆ˜κ°€ 정리λ₯Ό ν•˜λŠ” ν•¨μˆ˜μ΄λ‹€.

useEffect(() => {
  const subscription = props.source.subscribe();
  return () => {
    // Clean up the subscription
    subscription.unsubscribe();
  };
});

λ©”λͺ¨λ¦¬ 뢀쑱을 λ°©μ§€ν•˜ν•˜κΈ° μœ„ν•΄ μ»΄ν¬λ„ŒνŠΈκ°€ UI둜 λΆ€ν„° 제거되기 전에 μ‹€ν–‰ν•œλ‹€.

λ§Œμ•½μ— ꡬ독을 μ·¨μ†Œν•˜κΈ°μ „μ— λ‹€λ₯Έ effectκ°€ 싀행이 λ˜μ–΄ ꡬ독을 ν•œλ‹€λ©΄? μ΄λŸ¬ν•œ 일이 λ°œμƒν•˜λŠ” 것을 막고 μ‹Άλ‹€λ©΄?


2.2 Timing of effects

componentDidMount λ‚˜ componentDidUpdate κ³ΌλŠ” λ‹€λ₯΄κ²Œ layoutκ³Ό paint κ°€ λλ‚˜κ³  λ‚˜μ„œ useEffectκ°€ μ‹€ν–‰μ΄λœλ‹€. μ΄λ ‡κ²Œ λ˜λ‹ˆ λ§Œλ“  κ³΅ν†΅μ˜ λΆ€μž‘μš©μ— μžˆμ–΄μ„œ μ ν•©ν•˜λ‹€ 라고 ν•˜λŠ”λ°, ν™”λ©΄μ—μ„œ μ—…λ°μ΄νŠΈλ˜λŠ” 것이 λ©ˆμΆ”λŠ” ν˜„μƒμ΄ μΌμ–΄λ‚˜μ§€ μ•ŠμœΌλ‹ˆκΉŒ 그런 것이닀.

예λ₯Ό λ“€μ–΄, μ‚¬μš©μžκ°€ λ³Ό μˆ˜μžˆλŠ” DOM λ³€μ΄λŠ” μ‹œκ°μ μΈ 뢈일치λ₯Ό μΈμ‹ν•˜μ§€ λͺ»ν•˜λ„둝 λ‹€μŒ 페인트 전에 λ™κΈ°μ μœΌλ‘œ μ‹€ν–‰ν•΄μ•Ό ν•œλ‹€.

useLayoutEffect λŠ” useEffect λ™μΌν•œ κΈ°λŠ₯μ΄μ§€λ§Œ μ‹€ν–‰λ˜λŠ” μ‹œμ μ΄ λ‹€λ₯Έ Hook 이닀. μ‰½κ²Œ 말함면 μ‹€ν–‰λ˜λŠ” μ‹œμ μ΄ λ‹€λ₯΄λ‹€λŠ” 것인데 useEffect λŠ” μ•„λž˜μ— μ§„ν•œ 글씨와 같이 μ™„μ „νžˆ 화면이 κ·Έλ €μ‘Œλ‹€ λΌλŠ” 것을 보μž₯ν•  수 μžˆμ§€λ§Œ useLayoutEffectλŠ” μ‹œμ μ΄ Dom의 λ³€ν™”λŠ” μžˆμ§€λ§Œ repaint, reflowκ°€ λ˜μ§€ μ•Šμ€ μ‹œμ μ΄λΌκ³  μƒκ°ν•˜λ©΄ 될 것 κ°™λ‹€.

useEffectλŠ” λΈŒλΌμš°μ €κ°€ paintν• λ•Œ κΉŒμ§€ μ—°κΈ°λ₯Ό ν•˜μ§€λ§Œ μƒˆλ‘œμš΄ λ Œλ”λ§μ „μ— μ‹œμž‘λ  것이 λ³΄μ¦ν•œλ‹€.


2.3 Conditionally firing an effect

useEffect(
  () => {
    const subscription = props.source.subscribe();
    return () => {
      subscription.unsubscribe();
    };
  },
  [props.source],
);

useEffect μ—λŠ” 2번째 μΈμžκ°€ μ‘΄μž¬ν•œλ‹€. 여기에 λ“€μ–΄κ°€λŠ” 배열은 λ‚΄κ°€ 바라볼 것 으둜 μ—¬κΈ°μ„œλŠ” props.source 의 변경이 일어났을 κ²½μš°μ—λ§Œ μž‘λ™ν•˜κ²Œ λœλ‹€.

λ§Œμ•½μ— μΈμžμ— 아무것도 μ—†λ‹€λ©΄ λ§ˆμš΄νŠΈμ—μ„œ μ‹€ν–‰λ˜κ³  마운트 ν•΄μ œμ—μ„œλŠ” μ •λ¦¬ν•œλ‹€.


3. useContext()

    const context = useContext(Context);

react@16.3λΆ€ν„° 지원을 ν•œ Context λ₯Ό μ‚¬μš©ν•  수 μžˆλ„λ‘ μ§€μ›ν•˜λŠ” 것이닀. context object λ₯Ό λ°›μ•„μ„œ ν˜„μž¬ context 값을 λ°˜ν™˜ν•œλ‹€.

providerκ°€ μ—…λ°μ΄νŠΈλ˜λ©΄ Hooks이 μ‹€ν–‰λ˜μ–΄ μ΅œμ‹ μ˜ κ°’μœΌλ‘œ λ‹Ήμ—°νžˆ 동기화가 λœλ‹€.


Additional Hooks

4. useReducer

μš°λ¦¬κ°€ λ¦¬λ•μŠ€μ—μ„œ 많이 보던 Reducer 와 λΉ„μŠ·ν•˜λ‹€κ³  μƒκ°ν•˜λ©΄ λœλ‹€. κ·Έλ ‡λ‹€κ³  ν•œλ‹€.

    const initialState = {count: 0};
    
    // μš°λ¦¬κ°€ Reduxμ—μ„œ λ§Œλ“€λ˜ Reducer λΆ€λΆ„
    function reducer(state, action) {
      switch (action.type) {
        case 'increment':
          return {count: state.count + 1};
        case 'decrement':
          return {count: state.count - 1};
        default:
          throw new Error();
      }
    }
    
    function Counter({initialCount}) {
      // μ΄ˆκΈ°ν™” κ°’κ³Ό Reducerλ₯Ό λ„£μ–΄μ€€λ‹€.
      const [state, dispatch] = useReducer(reducer, initialState);

      return (
        <>
          Count: {state.count}
          <button onClick={() => dispatch({type: 'increment'})}>+</button>
          <button onClick={() => dispatch({type: 'decrement'})}>-</button>
        </>
      );
    }

4.1 Specifying the initial state

2번째 인자둜 μ΄ˆκΈ°ν™” state λ₯Ό λ„˜κ²¨μ€€λ‹€.(κ°„λ‹¨ν•˜κ²Œ μ΄ˆκΈ°ν™”ν•˜λŠ” 방법)

    const [state, dispatch] = useReducer(
        reducer,
        {count: initialCount}
      );

4.2 Lazy initialization

λ§Œμ•½ λŠμŠ¨ν•˜κ²Œ 초기 state λ₯Ό λ§Œλ“€κ³  μ‹Άλ‹€λ©΄ 3번째 인자둜 init function 을 λ„˜κΈ°μž

그러면 init(initialArg) μ΄λŸ°μ‹μœΌλ‘œ 호좜이 될 것이닀.

    function init(initialCount) {
      return {count: initialCount};
    }
    
    function reducer(state, action) {
      switch (action.type) {
        case 'increment':
          return {count: state.count + 1};
        case 'decrement':
          return {count: state.count - 1};
        case 'reset':
          return init(action.payload);
        default:
          throw new Error();
      }
    }
    
    function Counter({initialCount}) {
      const [state, dispatch] = useReducer(reducer, initialCount, init);
      return (
        <>
          Count: {state.count}
          <button
            onClick={() => dispatch({type: 'reset', payload: initialCount})}>
    
            Reset
          </button>
          <button onClick={() => dispatch({type: 'increment'})}>+</button>
          <button onClick={() => dispatch({type: 'decrement'})}>-</button>
        </>
      );
    }

4.3 Bailing out of a dispatch

useState 와 λ™μΌν•˜κ²Œ 같은 값을 λ„˜κΈ°κ²Œ 되면 λ‚΄λΆ€μ μœΌλ‘œ 비ꡐλ₯Ό ν•΄μ„œ μžμ‹ λ Œλ”λ§κ³Ό effectλ₯Ό μ‹€ν–‰ν•˜λŠ” 것을 λ§‰λŠ”λ‹€.


5. useCallback

    const memoizedCallback = useCallback(
      () => {
        doSomething(a, b);
      },
      [a, b],
    );

Returns a memoized callback.

인라인 콜백과 μž…λ ₯ 배열을 μ „λ‹¬ν•©λ‹ˆλ‹€. useCallback 은 μž…λ ₯ 쀑 ν•˜λ‚˜κ°€ λ³€κ²½λœ κ²½μš°μ—λ§Œ λ³€κ²½λ˜λŠ” 콜백의 memoized 버전을 λ°˜ν™˜ν•©λ‹ˆλ‹€

즉 a λ˜λŠ” b κ°€ 변경이 λ˜μ—ˆλ‹€λ©΄ ν•¨μˆ˜ κ²°κ³Όλ₯Ό λ°˜ν™˜ν•œλ‹€.

  • λ™μΌν•œ ν‘œν˜„
    useCallback(fn, inputs) //is equivalent to 
    useMemo(() => fn, inputs).

6. useMemo

    const memoizedValue = useMemo(() => computeExpensiveValue(a, b), [a, b]);

Returns a memoized value.

λ Œλ”λ§λ˜λŠ” λ™μ•ˆ 에 useMemo에 μ „λ‹¬λœ ν•¨μˆ˜κ°€ 싀행이 λœλ‹€.

즉, μ‚¬μš©ν•˜λŠ”λ° μžˆμ–΄μ„œ μ‘°μ‹¬ν•΄μ•Όν•œλ‹€. λ Œλ”λ§λ™μ•ˆ ν•˜μ§€μ•ŠλŠ” 것을 ν•˜μ§€ μ•Šμ•„μ•Όν•œλ‹€. side effectλ₯Ό μœ„ν•΄ useEffectλ₯Ό μ‚¬μš©ν•΄μ•Όν•˜λŠ” 것이닀.

useEffect 와 λ™μΌν•˜κ²Œ 배열이 λ„˜μ–΄κ°€μ§€ μ•Šμ„ 경우 λ§€μˆœκ°„ 첫번째 λ§€κ°œλ³€μˆ˜λ₯Ό νƒ€κ²Œ λœλ‹€.

μ„±λŠ₯ μ΅œμ ν™”λ₯Ό μœ„ν•΄μ„œ useMemoλ₯Ό μ‚¬μš©ν•  수 μžˆμ„ κ²ƒμœΌλ‘œ 생각이 λœλ‹€.


7. useRef

    function TextInputWithFocusButton() {
      const inputEl = useRef(null);
      const onButtonClick = () => {
        // `current` points to the mounted text input element
        inputEl.current.focus();
      };

      return (
        <>
          <input ref={inputEl} type="text" />
          <button onClick={onButtonClick}>Focus the input</button>
        </>);
    }

8. useImperativeHandle

    useImperativeHandle(ref, createHandle, [inputs])

useImperativeHandle 은 ref λ₯Ό μ‚¬μš©ν•  λ•Œ λΆ€λͺ¨ ꡬ성 μš”μ†Œμ— λ…ΈμΆœλ˜λŠ” μΈμŠ€ν„΄μŠ€ 값을 μ‚¬μš©μž μ •μ˜ν•©λ‹ˆλ‹€.

    function FancyInput(props, ref) {
      const inputRef = useRef();

      useImperativeHandle(ref, () => ({
        focus: () => {
          inputRef.current.focus();
        }
      }));

      return <input ref={inputRef} ... />;
    }
    FancyInput = forwardRef(FancyInput);

9. useLayoutEffect

μ„œλͺ…은 useEffect와 λ™μΌν•˜μ§€λ§Œ λͺ¨λ“  DOM 변이 후에 λ™κΈ°μ μœΌλ‘œ μ‹œμž‘ λ©λ‹ˆλ‹€.

useLayoutEffect λ‚΄λΆ€μ—μ„œ μ˜ˆμ•½λœ μ—…λ°μ΄νŠΈλŠ” λΈŒλΌμš°μ €κ°€ νŽ˜μΈνŠΈν•  수 있기 전에 λ™κΈ°μ μœΌλ‘œ ν”ŒλŸ¬μ‹œλ©λ‹ˆλ‹€.

이것을 μ‚¬μš©ν•˜μ—¬ DOMμ—μ„œ λ ˆμ΄μ•„μ›ƒμ„ 읽고 λ™κΈ°μ μœΌλ‘œ λ‹€μ‹œ λ Œλ”λ§ν•©λ‹ˆλ‹€.

μ‹œκ°μ μΈ μ—…λ°μ΄νŠΈλ₯Ό 막지 μ•Šλ„λ‘ useEffectλ₯Ό μ‚¬μš©ν•˜κΈ°λ₯Ό ꢌμž₯함


10. useDebugValue

useDebugValueλŠ” React DevToolsμ—μ„œ μ‚¬μš©μž μ •μ˜ 후크 λ ˆμ΄λΈ”μ„ ν‘œμ‹œν•˜λŠ” 데 μ‚¬μš©ν•  수 μžˆμŠ΅λ‹ˆλ‹€.

    function useFriendStatus(friendID) {
      const [isOnline, setIsOnline] = useState(null);
    
      // ...
    
      // Show a label in DevTools next to this Hook
      // e.g. "FriendStatus: Online"
      useDebugValue(isOnline ? 'Online' : 'Offline');
    
      return isOnline;
    }

10.1 Defer formatting debug values

    useDebugValue(date, date => date.toDateString());

Reference

-usehooks

About

This is place to study react-hook. Let's create custom hooks

Topics

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors