[React] - Hooks

Lee Jeong Min·2021년 12월 23일
0
post-thumbnail

Hooks

Hooks 사용 규칙

  1. React 함수 컴포넌트, 다른 커스텀 Hook 함수 안에서만 사용 가능하다. 일반 함수, 또는 클래스 컴포넌트 안에서 호출하면 안된다.
  2. Hook은 문 또는 중첩 또는 함수 안에서 사용할 수 없다.

참고사이트: https://ko.reactjs.org/docs/hooks-rules.html#explanation

상태 Hook

함수 컴포넌트에서 상태를 관리할 때 React.useState() 훅을 사용한다.

useState() 훅은 상태와 상태 업데이트를 담당하는 함수를 반환한다. 훅에 최초 전달된 값이 컴포넌트의 초기 상태 값이 되며, 함수 컴포넌트가 다시 렌더링 될 때는 항상 이전의 업데이트 된 상태 값이 최신 상태 값이 된다.

const [stateValue, stateUpdater] = useState(initialState);

지연된 초기화

initialState 인자는 함수 컴포넌트 초기 렌더링 시에만 사용된는 state 초깃값을 설정한다. 이후 다시 렌더링 될 때는 이 값이 무시된다. 만약 state 초깃값을 계산하는데 많은 시간이 필요한 경우 초기 렌더링 시에만 실행될 함수를 설정해 지연된 초기화 처리가 가능하다.

const [stateValue, setUpdater] = useState(() => {
	// 계산에 적지 않은 시간이 소요될 경우
	const initialState = fibonacci(30);

	// 계산 이후: 지연된 초기화의 처리 값을 반환
	return initialState;
});

localStorage에서 데이터 값을 읽어오는 경우 또한 지연된 초기화 방법을 사용한다.

실습

const initialization = () => {
  let countValueKey = 'euid-count';
  let value = localStorage.getItem('euid-count');
  if (!value) {
    localStorage.setItem(countValueKey, JSON.stringify({ count: 1000 }));
  }

  return value ? JSON.parse(value).count : 100;
};

export function TiltCardContainer(props) {
  // 상태 관리 (찌연된 초기화(함수) 활용)
  const [count] = useState(initialization);
  ...

상태관리를 할 시에 여러 상태를 묶어서 관리하는 방법 추천 X

  // [상태 관리]
  // 여러 상태를 묶어서 관리하는 방법 추천 X
  // 관심사의 분리가 되지 않기 때문이다.
  const [state] = useState({
    count: 10,
    name: 'JM',
  });

  return (
    <>
      <output>{state.count}</output> <output>{state.name}</output>

묶어서 관리를 하게 된다면, 성능 이슈 유발 (불필요한 리 렌더링 시도)

객체 타입의 상태 관리

useState()훅에서 클래스의 state, setState()와 동일하게 작동되도록 하려면 합성된 객체를 반환해야한다.

const [state, updateState] = useState({
	key1: false,
	key2: true
});

updateState({
	...state,
	key2: true
});

합성된 객체를 반환시키지 않으면 바로 그냥 설정한 상태 값으로 바뀌어 버림
이는 클래스의 setState 메서드와 useState의 update하는 함수의 동작 방식이 다르기 때문!

이펙트 함수

사이드 이펙트(비동기 통신 요청/응답, DOM 조작, 구독/취소 등)는 class 컴포넌트의 render 메서드에서는 다룰 수 없다. useEffect() 훅은 class 컴포넌트의 사이드 이펙트 관리 라이프 사이클 메서드 기능을 모두 처리한다.

useEffect(() => {
	// DOM 마운트(렌더링) 이후 콜백(실행)
});

이펙트 조건 처리

특정 조건에 따라 이펙트 함수를 실행해야 하는 경우, useEffect() 훅의 2번째 인자로 종속성 배열을 설정한다.

useEffect(
	() => {
		// componentDidMount
	}, 
	[]
);

관심사의 분리

  // [상태 관리]
  const [a, setA] = useState(1);
  useEffect(() => {
    console.group('종속성 배열에 a 가 변경된 경우');
    console.log('change a: ', a);
    console.groupEnd();
  }, [a]);

  // 관심사 Count
  const [count, setCount] = useState(10);
  useEffect(() => {
    console.group('종속성 배열에 count 가 업데이트 된 경우');
    console.log('change count: ', count);
    console.groupEnd();
  }, [count]);

  // 관심사 Name
  const [name, setName] = useState('euid');
  useEffect(() => {
    console.group('종속성 배열에 state.name 이 업데이트 된 경우');
    console.log('change name: ', name);
    console.groupEnd();
  }, [name]);

클래스 컴포넌트와 다르게 useEffect를 사용하여 상태와 행위를 관심사를 분리하여 나눌 수 있다. 또한 이를 빼내어 커스텀 훅을 만들어 어디서나 재사용할 수 있는 컴포넌트를 만들 수 있다.

클린업

이펙트 함수를 통해 설정된 사이드 이펙트는 컴포넌트가 UI에서 제거될 때 정리되어야한다.
이를 수행하기 위해 이펙트 함수에서 클린업 함수를 반환하고 그 함수 내부에서 정리를 실행한다.

useEffect(
	() => {
		// 구독
		return () => {
			// 정리(cleanup) 함수
			// 구독 취소
		}
	},
	[]
);

이는 메모리 누수 방지를 위해 UI에서 컴포넌트를 제거 하는 직전에 수행된다. 이는 class 컴포넌트의 componentWillUnmount와 유사하게 동작한다고 볼 수 있지만, 실상은 다음 이펙트 함수가 실행될 때마다 클린업 함수가 먼저 실행되어 정리한다.

렌더링 될때마다 클린업 함수가 실행되는 이유

참고 사이트: https://ko.reactjs.org/docs/hooks-effect.html#explanation-why-effects-run-on-each-update

React Hook 실행 흐름

proptypes

참고 사이트: https://www.npmjs.com/package/prop-types

패키지 설치

yarn add prop-types

참고사이트: https://ko.reactjs.org/docs/typechecking-with-proptypes.html#gatsby-focus-wrapper

SkHeading.propTypes = {
  className: PropTypes.string,
  as: PropTypes.string.isRequired,
  children: PropTypes.string.isRequired,
};

isRequired가 들어오게 된다면 필수적이라는 의미

useRef()

mutation 방식이어서 리렌더링 발생 X
useRef의 쓰임새
1. DOM 노드 참조
2. 컴포넌트 렌더링에 영향을 미칮 않으면서 임의의 값을 매 렌더링 시마다 기억하고자 할 때

React의 ref는 주로 DOM 노드 참조 목적으로 사용되지만 컴포넌트 렌더링에 영향을 주지 안흔 값 참조 목적으로 사용된다. React.useRef() 훅은 함수 컴포넌트 내부에서 특정 값을 지속적으로 참조할 때 사용한다.
React.useState() 훅과 달리, useRef() 훅은 현재(current) 값이 변경되어도 컴포넌트가 다시 렌더링되지 않아 애플리케이션 성능을 최적화 할 수 있다.

// useRef() 훅을 사용해 카운트 참조 생성
const countRef = useRef(0);

// 카운트 참조의 현재 값이 변경되어도 컴포넌트는 다시 렌더링 되지 않음
countRef.current = countRef.current + 1;

참고사이트: https://ko.reactjs.org/docs/hooks-reference.html#useref

useCallback

참고사이트: https://ko.reactjs.org/docs/hooks-reference.html#usecallback

profile
It is possible for ordinary people to choose to be extraordinary.

0개의 댓글