6. hook -2

리리·2021년 8월 13일

TIL

목록 보기
20/22

useMemo

동일한 연산의 반복 수행을 제거해서 성능을 최적화하는데 사용.

useMemo(() => {}, []);
// 첫 번째 파라미터: 함수
// 두 번째 파라미터: 함수 실행조건을 배열로 전달하면 지정된 값에 변화가 있는 경우에만 함수가 호출된다.

javascript, expo, expo, react native라고 적혀있는 list를 버튼을 클릭할때마다 다음 리스트의 값과 값의 길이를 가져온다.

const getLength = text => {
  console.log(`Target Text: ${text}`);
  return text.length;
};

const list = ['JavaScript', 'Expo', 'Expo', 'React Native'];

let idx = 0;
const Length = () => {
  const [text, setText] = useState(list[0]);
  const [length, setLength] = useState('');
  //버튼을 클릭할 때마다 list 다음 값을 가져온다. 
  const _onPress = () => {
    setLength(getLength(text));
    ++idx;
    if (idx < list.length) setText(list[idx]);
  };

  return (
    <>
      <StyledText>Text: {text}</StyledText>
      <StyledText>Length: {length}</StyledText>
      <Button title="Get Length" onPress={_onPress} />
    </>
  );
};

export default Length;

위의 경우, 마지막 문자열 이후에 더이상 문자열의 변화가 없지만 계속 문자열의 길이를 계산하는 getLength함수를 호출한다. 이런 상황에서 useMemo를 이용하면 계산하는 값에 변화가 있는 경우에만 함수가 호출되도록 중복되는 연산을 제거할 수 있다. length 컴포넌트에 useMemo를 사용해서 계산할 값에 변화가 없는 경우 etLength 함수가 호출되지 않도록 수정한다.

const _onPress = () => {
    //setLength(getLength(text));
    ++idx;
    if (idx < list.length) setText(list[idx]);
  };
  const length = useMemo(() => getLength(text), [text]);

useMemo를 이용해서 text값이 변화될 경우에만 text길이를 수정하도록 하였다.

2. 커스텀 hooks 만들기

hook 함수란? 특정 API에 GET 요청을 보내고 응답을 받는 함수이다. 리액트 네이티브에서는 네트워크 통신을 위해 Fetch와 SMLHttpRequest를 제공하고, 추가적으로 WebSocket도 지원한다. 이번에는 Fetch를 이용해서 useFetch라는 이름의 hook을 만든다.

api = application programming interface로 대충 사용자 - 데이터베이스 사이에 있는 통로? 같은거라고 생각됨.

fetch: make JS interface accessing and manipulating HTTP pipeline. 즉 http 통신코드. 서버에서 데이터를 받아온다.

useFetch.js

import { useState, useEffect } from 'react';

export const useFetch = url => {
  const [data, setData] = useState(null);
  const [error, setError] = useState(null);
  const [inProgress, setInProgress] = useState(false);

  useEffect(async () => {
	//async = 항상 promise를 반환한다.
    try {
      const res = await fetch(url);
			//await : async함수 안에서만 동작. promise가 처리될때까지 기다린다. 영어로 기다린다는 뜻을 갖고 있다. 여기선 fetch(url)이 동작할 때까지 기다린다. 
      const result = await res.json();
      if (res.ok) {
        setData(result);
        setError(null);
      } else {
        throw result;
      }
    } catch (error) {
      setError(error);
    }
  }, []);

  return { data, error, inProgress };
};

useEffect의 첫 번째 파라미터로 비동기 함수가 전달되었다는 부분이 경고 메세지로 뜬다.

Warning: An effect function must not return anything besides a function, which is used for clean-up. ...

비동기 함수를 이용해야하는 상황에서는 useEffect에 전달되는 함수 내부에 비동기 함수를 정의하고 사용하는 방법으로 이 문제를 해결 가능.

useEffect(() => {
    const fetchData = async () => {
      try {
        const res = await fetch(url);
        const result = await res.json();
        if (res.ok) {
          setData(result);
          setError(null);
        } else {
          throw result;
        }
      } catch (error) {
        setError(error);
      } 
    };
    fetchData();
  }, []);

  return { data, error };
};

API 요청을 보내는 비동기 동작에서는 선행된 작업이 마무리되기 전에 추가적인 요청이 들어오지 않도록 화면을 구성한다. useFetch로부터 API 요청의 진행 상태를 알 수 있어야 비동기 요청의 진행 상태를 알 수 있어야 비동기 요청의 작업 상태에 따라 화면 구성을 다르게 할 수 있다.

useFetch.js

export const useFetch = url => {
	...
  const [inProgress, setInProgress] = useState(false);

  useEffect(() => {
    const fetchData = async () => {
      try {
        setInProgress(true);
        ...
      } catch (error) {
        setError(error);
      } finally {
        setInProgress(false);
      }
    };
    fetchData();
  }, []);

  return { data, error, inProgress };
};

0개의 댓글