[ React ] 리액트 공식 문서 - HOOK

·2023년 8월 24일

Hook

함수 컴포넌트에서 React state의 생명 주기 기능을 '연동'할 수 있게 해주는 함수
class 대신 React를 사용할 수 있게 도와줌

Hook 사용규칙

  • 최상위 에서만 Hook을 호출해야 함. 반복문, 조건문, 중첩된 함수 내에서는 불가 : React가 Hook이 호출되는 순서에 의존하므로, 호출 순서가 달라지게 된다면 버그를 발생시킴
  • React 함수 컴포넌트 내에서만 Hook을 호출해야 함, 일반 JS함수에서는 불가능 (custom Hook) 제외

State Hook

useState : state를 함수 컴포넌트 안에서 사용할 수 있게 해줌

useState 사용 방법

  1. state 선언하기
import React, {useState} from 'react';

function Example() {
  const [count, setCount] = useState(0);
  • useState의 인자: state의 초기 값
  • useState가 반환하는 것: state 변수, 해당 변수를 갱신할 수 있는 함수(setCount가 호출됨)
  • 배열 구조 할당 방식으로 나타남
var fruitStateVariable = useState('banana');
var fruit = fruitStateVariable[0];
var setFruit = fruitStateVariable[1];
  1. state 가져오기
    함수 컴포넌트는 this.state.count 대신 count를 직접 사용할 수 있음
<p>You clicked {count} times</p>
  1. state 갱신하기
    함수 컴포넌트는 setCountcount 변수를 가지고 있으므로 this를 호출하지 않아도 됨
<button onClick={() => setCount(count+1)}>
  Click me!
</button>

Effect Hook

side effects(컴포넌트 안에서 데이터를 가져오거나 구독하고 DOM을 직접 조작하는 작업과 같이 다른 컴포넌트에 영향을 주는 작업)를 수행할 수 있게 해줌 <b>useEffect</b> React class의 componentDidMount, componentDidUpdate, componentWillUnmount`가 하나의 API로 통합된 것

useEffect

useEffect를 사용하여 React에게 컴포넌트가 렌더링 이후에 어떤 일을 수행해야 하는 지를 알려줌 React는 우리가 넘긴 함수(effect)를 기억했다가 DOM 업데이트를 수행한 이후 불러냄

function Example() {
  const [count, setCount] = useState(0);
  
  useEffect(() => {
    document.title = `You cliked ${count} times`;
  });
}

이때 useEffect 안에 함수를 전달함 이때의 함수가 effect
같은 함수 내부에 있기 때문에 최신의 count를 바로 얻을 수 있음
리렌더링 때마다 이전과 다른 effect로 교체해서 전달

effect에서 함수를 반환한다면?

이는 effect를 위한 추가적인 정리(clean-up) 메커니즘임
따라서 컴포넌트 마운트가 해제되는 때 정리를 실행함

useEffect (()=> {
  function handleStatusChange(status){
    setIsOnline(status.isOnline);
  }
  ChatAPI.subscriptToFriendStatus(props.friend.id, handleStatusChange);
  return() => {
    ChatAPI.unsubscribeFromFriendStatus(props.friend.id, handleStatusChange);
  };
});

Hook api

useState

상태 유지 값과 그 값을 갱신하는 함수를 반환
최초 렌더링 시, 반환된 state는 첫 번째 전달된 인자의 값과 같음

함수적 갱신

이전 state를 사용해서 새로운 state를 계산하는 경우 함수를 setState로 전달함
따라서 setState는 이전 값을 받아 갱신된 값을 반환

지연 초기 state

initalState 는 초기 렌더링 시에 사용하는 state으로 이후 렌더링 시 무시됨

예시로 살펴보자

function Counter({initalState}) {
  const [count, setCount ] =useState(initalCount);
  return (
    <>
	    Count: {count}
		<button onClick={() => setCount(initalCount)}>Reset</button>
		<button onClick={() => setCount(prevCount => prevCount -1)}> - </button>
	);
}

useEffect

명령형 또는 어떤 effect를 발생하는 함수를 인자로 받음
useEffect로 전달된 정리 함수는 UI에서 컴포넌트를 제거하기 전에 수행됨 (clean-up)
useEffect에 전달된 함수는 화면에 렌더링이 완료된 후(레이아웃 배치와 그리기를 완료한 후)에 수행됨

예시로 살펴보자

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

조건부 effect 발생

effect가 종속되어 있는 값의 배열인 useEffect 의 두번째 인자를 전달하여, 해당 배열이 변경될 때 effect가 일어남, 이때 빈 배열을 전달하면 props나 state에서 가져온 어떤 값에도 의존하지 않으므로, 다시 실행할 필요가 전혀 없음

예시로 살펴보자

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

useContext

const value = useContext(MyContext);

context 객체를 받아 context의 현재 값을 반환, 이때 context의 현재 값은 Hook을 호출하는 컴포넌트에 가장 가까이 있는 <MyContext.Provider>value prop에 의해 결정됨
이때, <MyContext.Provider> 가 갱신되면 가장 최신의 context value를 사용하여 재랜더링을 시킴, 즉 useContext를 구독하고 있는 컴포넌트 자체에서부터 재랜더링

예시로 살펴보자

const themes = {
  light: {
    foreground: '#000000",
    background: "#eeeeee"
  }, 
  dark: {
    foreground: "#ffffff",
    background: "#222222"
  }
};

const ThemeContext = React.createContext(themes.lignt);

function App() {
  return (
    <ThemeContext.Provider value = {themes.dark}>
    	<Toolbar/>
    </ThemeContext.Provider>
	);
}

function ThemedButton() {
  const theme = useContext(ThemeContext);
  return (
    <button style={{ background: theme.background, color: theme.foreground}}>
    	I am styled by theme context!
    </button>
	);
}

useReducer

const [state, dispatch] = useReducer(reducer, initalArg, init);

useState의 대체 함수로,
(state, action) => newState 형태로 reducer를 받고 dispatch 메서드와 짝의 형태로 현재 state를 반환
다수의 하윗값을 포함하는 복잡한 정적 로직을 만드는 경우나 다음 state가 이전 state에 의존적인 경우 보통 useReducer 사용
initalArg: 초기 state를 두 번째 인자로 전달
init(initalArg) : 초기 state 지연해서 생성

예시로 살펴보자


const init(initalCount) {
  return {count:initalCount};
}

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({initalCount}) {
  const [state, dispatch] = useReducer(reducer, initalCount, init);
  return (
    <>
    	Count: {state.count}
		<button onClick={() => dispatch({type: 'reset', payload: initalCount})}>Reset</button>
		<button onClick={() => dispatch({type: 'decrement'})}>-</button>
		<button onClick={() => dispatch({type: 'increment'})}>+</button>
	</>
  );
}
                                        

useCallback

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

메모이제이션된 콜백을 반환, useCallback은 콜백의 메모이제이션된 버전을 반환함
메모이제이션된 버전은 콜백의 의존성이 변경되었을 때에만 변경됨

useMemo

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

메모이제이션된 값을 반환, 생성함수와 그것의 의존성 값의 배열을 전달
useMemo는 의존성이 변경되었을 때에만 메모이제이션된 값을 다시 계산함
useMemo로 전달된 함수는 렌더링 중에 실행됨.

useRef

const refContainer = useRef(initalValue);

useRef.current 프로퍼티로 전달된 인자로 초기화된 변경 가능한 ref 객체를 반환함
useRef.current 프로퍼티에 변경 가능한 값을 담고있는 '상자' 와 같음
useRef는 매번 렌더링할 때 동안 동일한 ref 객체를 제공

예시로 살펴보자

function TextInputWithFocusButton() {
  const inputE1 = useRef(null);
  const onButtonClick = () => {
    inputE1.current.focus();
  };
  return (
    <>
    	<input ref={inputE1} type='text'/>
    	<button onClick={onButtonClick}>Focus the input</button>
	</>
 );
}
profile
new blog: https://hae0-02ni.tistory.com/

0개의 댓글