리액트 공식 문서 정리- Hook API, Hook 자주 묻는 질문, 리액트 자주 묻는 질문

Jessie H·2022년 9월 9일
0

react

목록 보기
13/13
post-thumbnail

hook api

useState

  • state 값과 state를 업데이트하는 함수를 반환
  • 변수 작명 시 camelCase 적용
  • 첫 렌더링 시 반환된 state는 state 초기값과 같음
const [(state변수명), set(state변수명)] = useState(초기값);
  • set + (state변수명)은 state를 업데이트 할 때 사용
    setState(새 state값 or state 연산)
  • 다음 리렌더링 시 useState를 통해 반환받은 첫번째 값은 항상 갱신된 최신 state임
  • react가 setState 함수가 동일, 안정적, 불변함을 보장함
  • useState는 업데이트된 객체를 자동으로 합치지 않기 떄문에 이전 것 뒤에 업데이트 되게 하려면 전개 연산자로 결합시켜야함
const [state, setState] = useState({});
setState((prev) => {
  return {...prev, ...updatedValues};
});
  • react 18버전부터는 모든 state 업데이트에 대해 일괄적으로 처리함
    (예: 하나의 클릭 이벤트 안에 두 개의 state 업데이트가 포함되어 있다면 두 개의 state 업데이트를 한꺼번에 적용한다)
    --> 불필요한 리렌더링 감소

위 내용에 관련된 예시

//..생략
const handleClick = () => {
  setCount((count) => count + 1);
  setIsClicked((clicked) => !clicked);
  //setIsClicked까지 끝나야 리렌더링 함
}
  • 현재의 state값과 동일한 값으로 갱신하는 경우에는 렌더링x

출처: https://immigration9.github.io/react/2021/06/12/automatic-batching-react.html

useEffect

  • 명령형 또는 side effect 발생 함수를 첫번째 인자로, 두번째 인자로는 dependency를 받는다
    (dependency는 선택, dependency없을 경우 매 렌더링 시 마다 useEffect가 실행된다)
    참고: 명령형 vs 선언형
function ex() {
  const [state, setState] = useState(0);
  
  useEffect(() => {
  	fetch(~~~어쩌구저쩌구 URL);
  }, [state]);
  //state가 업데이트 될 때만 useEffect가 실행된다.
  
  useEffect(() => {
   //...생략
  }, []);
  //dependency로 빈 배열을 넣을 경우, useEffect가 최초 렌더링 시 1회만 실행된다
  
  //...생략
}
  • 렌더링 된 후에 실행
  • dependency 설정 후에는 dependency로 둔 값이 변경되었을 때만 실행
  • 타이머, 구독 id같이 렌더링 마다 제거가 되어야하는 경우 clean-up함수를 통해 갱신되긴 전 제거시킬 수 있다
useEffect(() => {
  //...생략
  return () => {
    //clean-up 부분
  }
}, [state]);

useCallback

  • 메모제이션된 콜백을 반환
    (컴포넌트 내에서 선언된 함수가 매 렌더링마다 재선언되지 않도록 고정시킨다고 보면 된다)
  • dependency를 두번째 인자로 받고, 이 인자가 업데이트 될 때만 새로 선언된다
const callbackFunc = () => {
  console.log("be declared whenever it renders");
};
//이 함수는 렌더링 될 때마다 재선언되기 때문에 메모리 낭비가 일어남

const funcWrapped = useCallback(() => {
  console.log("be declared only at the first rendering");
}, []);
//이 함수는 첫 렌더링 시에만 선언되고 더 이상 재선언되지 않음

useMemo

  • 메모제이션된 값을 반환
  • 고비용의 계산을 하는 함수가 매 렌더링 시 계산을 하지 않도록 할 수 있음
    (고비용의 계산: 시간이 오래걸리고 메모리 많이 잡아먹는 연산 같은게 들어가 있는 처리)
  • dependency가 업데이트 될 때만 콜백함수를 실행해 반환값 계산함
const memoizedValue = useMemo(() => {
  expensiveProcess(productNum)
}, [productNum]); 
  • useMemo로 전달된 함수는 렌더링 중에 실행됨
  • side Effect는 여기다 넣으면 안됨(useEffect에 넣을 것)

useRef

const ref변수명 = useRef(초기값);
//ref변수명 = { current: 초기값 }
//ref 변수명은 맘대로 정할 수 있음
  • 초기값은 전 생애주기를 통해 유지
    (컴포넌트가 계속 렌더링 되어도 ref값은 컴포넌트가 unmount될 때까지 유지됨)
  • ref 수정방법: ref변수.current = ref변수.current + 1과 같이 변경
  • 사용하는 경우: 변화는 감지해야하는데 변화가 렌더링을 발생시키면 안되는 경우
    • 저장공간으로 사용: 컴포넌트가 렌더링 되면 내부 변수들은 모두 초기화가 되지만 ref는 초기화되지 않고 그대로 유지됨
    • DOM요소에 접근: 바닐라자스의 document.querySelector()같은 역할임
      ex) input요소를 클릭하지 않고 focus 주고 싶을 때

참고: https://www.youtube.com/watch?v=VxqZrL4FLz8&ab_channel=%EB%B3%84%EC%BD%94%EB%94%A9


hook 자주 묻는 질문

이전 props 또는 state를 얻는 법

  • useRef 사용하여 수동으로 얻기
function Counter() {
  const [count, setCount] = useState(0);

  const prevCountRef = useRef();
  useEffect(() => {
    prevCountRef.current = count;
  });
  const prevCount = prevCountRef.current;

  return <h1>Now: {count}, before: {prevCount}</h1>;
}
  • 커스텀 훅으로 얻기
function usePrevious(value) {
  const ref = useRef();
  useEffect(() => {
    ref.current = value;
  });
  return ref.current;
}

function Counter() {
  const [count, setCount] = useState(0);
  const prevCount = usePrevious(count);
  return <h1>Now: {count}, before: {prevCount}</h1>;
}

effect 종속성이 너무 자주 변경될 때

예시)

function Counter() {
  const [count, setCount] = useState(0);
  
  useEffect(() => {
    const id = setInterval(() => {
      setCount(count + 1); 
      // 이 effect는 'count' state에 따라 달라짐
    }, 1000);
    
    return () => clearInterval(id);
  }, [count]); 
  // 이렇게 되면 매번 렌더링마다 setInterval의 타이머가 
  // 클린업 되었다가 재설정되기 때문에 setInterval이 아니라 setTimeout처럼 실행됨

  return <h1>{count}</h1>;
}
function Counter() {
  const [count, setCount] = useState(0);

  useEffect(() => {
    const id = setInterval(() => {
      setCount(c => c + 1); 
      // ✅ 이것은 외부의 'count' 변수에 의존하지 않고 
      // 이전 값을 참조하여 count를 업데이트 함
    }, 1000);
    
    return () => clearInterval(id);
  }, []); 
  //setInterval 자체는 최초 렌더링 시 즉, 1번만 실행이 되지만 
  // 그 안에 있는 setCount는 1초마다 이전 값을 참조하여 count를 계속 업데이트 하게 된다 

  return <h1>{count}</h1>;
}

useCallback에서 자주 변경되는 값을 읽는 법

function Form() {
  const [text, updateText] = useState('');
  const textRef = useRef();

  useEffect(() => {
    textRef.current = text; 
  });
  // ref에 input으로 입력한 값 저장
  // ref 값은 렌더링마다 재선언되지 않고 그대로 유지되고, 렌더링 발생시키지 않음

  const handleSubmit = useCallback(() => {
    const currentText = textRef.current; 
    // ref값을 currentText 변수에 저장
    alert(currentText);
  }, [textRef]); 
  //handleSubmit 함수는 textRef가 변경될 때만 다시 선언된다
  // handleSubmit 함수는 textRef 값을 제출했을 때만 실행됨
  // textRef는 렌더링 될때에도 유지되기 때문에 useCallback이 자주 재선언되지 않아 메모리 낭비 줄이기 가능
  

  return (
    <>
      <input value={text} onChange={e => updateText(e.target.value)} />
      <ExpensiveTree onSubmit={handleSubmit} />
    </>
  );
}

리액트 자주 묻는 질문

AJAX 호출과 API

  • fetch나 axios 써서 호출 가능
  • fetch쓰는 법
useEffect(()=>{
  fetch(get요청할 URL)
    .then(res => res.json())
    .then(
      (result) => {
        setIsLoaded(true);
        setItems(result);
      },
      (error) => {
        setIsloaded(true);
        setError(error);
      }
      //에러 처리 시 try catch보다는 then으로 error다루는게 나음
    )
}, [])
  • axios 쓰는 법
  1. axios 설치
npm install axios
  1. axio import하고 url로 get요청하기
import axios from "axios";

function App () {
  useEffect(() => {
   axios.get(URL적기)
    .then((result) => console.log(result.data))
    //result.data에 axios로 가져온 데이터 들어있음
    .catch((error) => console.log(error));
  }, []);
}

파일 구조

  • 파일 기능에 따라 분류: common/profile/feed/stroe
  • 파일 유형에 따라 분류: api/component/store
  • 잘 모르겠다면 먼저 하나의 파일에 다 개발해보고 나누고 싶을 때 나눠보는 것도 좋은 방법임
  • 디렉토리 중첩은 3-4회까지만 괜찮고 그 이상은 에바임
    (페이지 - (페이지 제목 + 페이지 리스트 - (리스트 내용 + 리스트 사진..)))

virtual DOM

  • DOM과 똑같은 복제 형태의 DOM
  • react 프로젝트에서는 항상 virtual DOM이 형성됨
  • 리액트의 렌더링 과정
    • 업데이트 발생 시 바로 DOM에 반영되는 것이 아니라 업데이트 될 때마다 virtual DOM에 먼저 다 업데이트를 함
    • 그리고 초기 virtual DOM과 업데이트 된 virtual DOM의 차이점을 비교하고 차이점을 DOM에 최종 update & repaint함
사진 출처: https://blog.logrocket.com/what-virtual-dom-react/
profile
코딩 공부 기록장

0개의 댓글