처음 배우는 리액트 네이티브

6장 Hooks

youbing 2025. 1. 23. 00:38
  • 이전에는 컴포넌트의 상태를 관리하거나 생명 주기에 따라 특정 작업을 수행하려면 클래스형 컴포넌트를 사용해야 했음.
  • 하지만 Hooks를 이용할 수 있게 되면서 함수형 컴포넌트에서도 상태를 관리할 수 있게 되었고 컴포넌트의 생명 주기에 맞춰 특정 작업을 수행할 수 있게 됨.

 

6.1 useState

const [state, setState] = useState(initialState);
  • return : [변수, 세터 함수]
    • 세터 함수 : 변수를 수정할 수 있는 함수
  • useState 함수는 관리해야 하는 상태의 수만큼 여러 번 사용할 수 있음.
  • 상태를 관리하는 변수는 반드시 세터 함수를 이용해 값을 변경해야 함 -> 상태가 변경되면 컴포넌트가 변경된 내용을 반영하여 재렌더링 됨.

 

세터 함수

  1. 세터 함수에 변경될 상태의 값을 전달 ( setState(newState) )
  2. 세터 함수의 파라미터에 함수를 전달 ( setState(prevState => {}) )
  • 세터 함수는 비동기로 동작하기 때문에 세터 함수를 호출해도 바로 상태가 변경되지 않는 문제점이 있음.

-> 상태에 대해 여러 업데이트가 함께 발생할 경우, 2번 방법으로 함수를 인자로 전달하면 문제 해결


6.2 useEffect

useEffect(() => {}, []);
  • 1번째 파라미터 : 함수 - 조건을 만족할 때마다 호출
  • 2번째 파라미터 : (의존성) 배열 - 함수가 호출되는 조건 설정
    • 의존성 배열 X : 컴포넌트가 렌더링될 때마다 호출 / cleanup 함수도 같이 실행
    • [변수] :  그 변수의 상태가 변경되었을 때만 호출 / cleanup 함수가 실행된 뒤 새로운 Effect 실행
    • [ ] : 컴포넌트가 처음 생성(mount)되었을 때 1번만 호출 / cleanup 함수는 언마운트(unmount)될 때 실행
  • 상태의 값을 변경하는 세터 함수가 비동기로 동작하므로 상태의 값이 변경되면 실행할 함수를 useEffect로 정의해야 함.

6.3 useRef

  • 특정 컴포넌트를 선택해서 포커스를 설정하고 싶은 경우 등에 사용
const ref = useRef(initialValue);
// 예시 : TextInput 컴포넌트 포커스 옮기기
const Form = () => {
  const refName = useRef(null);
  const refEmail = useRef(null);
  ...
  
  useEffect(() => {
    refName.current.focus();
  }, []);
  
  ...
  
  return (
    ...
    <StyledTextInput
      ref={refName}
      onSubmitEditing={() => refEmail.current.focus()}
      ...
    />
    <StyledTextInput
      ref={refEmail}
      ...
    />
  );
};

 

주의

  1. 컴포넌트의 ref로 지정하면 생성된 변수에 값이 저장되는 것이 아니라 변수의 .current property에 해당 값을 담음.
  2. useRef의 내용이 변경되어도 재렌더링 되지 않음.

6.4 useMemo

  • 동일한 연산의 반복 수행을 제거해서 성능 최적화
useMemo(() => {}, []);
  • 1번째 파라미터 : 함수 - 조건을 만족할 때마다 호출
  • 2번째 파라미터 : (의존성) 배열 - 함수가 호출되는 조건 설정
// 예시 : 배열을 순회하며 요소(문자열)의 길이 재기
const list = ['JavaScript', 'Expo', 'React Native'];

const getLength = text => text.length;

let idx = 0;
const Length = () => {
  const [text, setText] = useState(list[0]);

  const onPress = () => {
    setLength(getLength(text));
    ++idx;
    if (idx < list.length) setText(list[idx]);
  };
  
  const length = useMemo(() => getLength(text), [text]);
  
  return (
    <>
      <Text>text : {text}</Text>
      <Text>length : {length}</Text>
      <Button title='Get Length' onPress={onPress} />
    </>
  );
};

6.5 커스텀 Hooks 만들기

목표 : 특정 API에 GET 요청을 보내고 응답을 받는 함수 (Fetch를 이용하여 useFetch 만들기)

  • React Native는 네트워크 통신을 위해 FetchXMLHttpRequest를 제공하고, 추가적으로 WebSocket도 지원함.
// 예시 : useFetch
// src/hooks/useFetch.js
export const useFetch = url => {
  const [data, setData] = useState(null);
  const [error, setError] = useState(null);
  const [inProgress, setInProgress] = useState(false);
  
  useEffect(() => {
    const fetchData = async () => {
      try {
        setInProgress(true);
        const res = await fetch(url);
        const result = await res.json();
        if (res.ok) {
          setData(result);
          setError(null);
        } else {
          throw result;
        }
      } catch (e) {
        setError(error);
      } finally {
        setInProgress(false);
      }
    };
    fetchData();
  }, []);
  
  return { data, error, inProgress };
};
// src/components/Dog.js
const URL= '~~';
const Dog = () => {
  const { data, error, inProgress } = useFetch(URL);
  
  return (
    <>
      {inProgress && (
        <Text>The API request is in progress.</Text>
      )}
      <Image source={data?.message ? { uri: data.message } : null} />
      <Text>{error?.message}<Text>
    </>
  );
};

 

 

 

본문에서 설명하는 내용과 사용한 이미지는 책 '처음 배우는 리액트 네이티브'를 참고하였습니다.