TIL

[PB] 4주차 스터디 정리

팝삐 2024. 7. 21. 18:24

리액트로 데이터 다루기

배열 렌더링하기

배열을 렌더링할 땐 key를 기억

  • map을 통해 컴포넌트를 만들 때는 고유한 값을 가진 id를 지정해야 한다.
  • 배열의 idx는 key로 사용할 수 없음
function ReviewList({ items, onDelete }) {
  return (
    <ul>
      {items.map((item) => {
        return (
          **<li key={item.id}>**
            <ReviewListItem
              item={item}
              onDelete={onDelete}
            />
            <input></input>
          </li>
        );
      })}
    </ul>
  );
}

key를 써야 하는 이유

  • 고유하지 않은 값으로 key를 설정하지 않는 경우 렌더링이 잘못 일어날 수 있다.
  • 요소마다 고유한 값을 지정하고 나면 결과만 보고도 배열이 어떻게 변화했는 지 이해할 수 있다.
    • 그래서 고유한 값으로 key를 지정하는 것!

데이터 가져오기

fetch 사용하기

<aside> 📄 **Axios와 fetch의 차이 ?

  • axios는 사용하기 좀 더 편리하다
  • fetch에는 존재하지 않는 기능이 좀 더 많다
  • promise based
  • axio는 json을 자동으로 적용해서 response 객체를 반환
  • axios는 data를 바로 전달
  • 요청을 중도 Cancel, 응답시간 초과 설정 등의 기능이 있다.
  • fetch는 import가 필요없다.
  • 업데이트가 잦은 경우에도 fetch는 걱정 없다.
  • request aborting에 대해서 표준적인 방법을 제공해 주지 못한다.
  • response timeout API 제공이 되지 않는다.
  • error handling 관련 문**

</aside>

useEffect로 초기 데이터 가져오기

  • useEffect
    • 함수 실행을 useEffect로 대체해서 초기에 단 한 번 함수를 호출하도록 사용할 수 있다.
    • 무한 루프를 방지하기 위함이다.
  • 처음 한 번만 실행하기
  • useEffect(() => { // 실행할 코드 }, []);
  • 값이 바뀔 때마다 실행하기
  • useEffect(() => { // 실행할 코드 }, [dep1, dep2, dep3, ...]);

페이지네이션

  • 오프셋 기반 페이지네이션
    • = 상쇄하다
    • = 지금까지 받아온 데잍를 상쇄
    • ex) 20개를 받았으니까 10개 더 보내줘;
    • 개수 기반으로 데이터를 나누는 것.
  • 커서 기반 페이지 네이션
    • =데이터를 가리키는 값
    • =지금까지 받은 데이터를 표시한 책갈피
    • 다음 커서 값을 함께 보내 커서 값을 통해 서버에서 페이지를 호출한다.
    ⇒ 오프셋이랑 달리 데이터 중복 없이 호출할 수 있다.

네트워크 로딩 처리하기

  • 네트워크를 처리하는 동안 특정 기능을 막아 사용자 경험을 증가시킬 수 있다.
  • const handleLoad = async (options) => { let result; try { setIsLoading(true); result = await getReviews(options); } catch (error) { console.error(error); return; } finally { setIsLoading(false); } const { paging, reviews } = result; if (options.offset === 0) { setItems(reviews); } else { setItems((prevItems) => [...prevItems, ...reviews]); } setOffset(options.offset + options.limit); setHasNext(paging.hasNext); };

네트워크 에러 처리하기

const handleLoad = async (options) => {
    let result;
    try {
      setIsLoading(true);
      result = await getReviews(options);
    } catch (error) {
      **setLoadingError(error);**
      return;
    } finally {
      setIsLoading(false);
    }

    const { paging, reviews } = result;
    if (options.offset === 0) {
      setItems(reviews);
    } else {
      setItems((prevItems) => [...prevItems, ...reviews]);
    }
    setOffset(options.offset + options.limit);
    setHasNext(paging.hasNext);
  };

입력 폼 다루기

리액트에서 입력 폼 만들기

<aside> 📄 - JS 에서의 onChange는 사용자가 input을 변경한 후 focus out이 발생할 때 발생

  • 리액트에서의 onChange = JS의 onInput과 동일하게 사용(Input값이 변경 시마다)

</aside>

하나의 state로 폼 구현하기

  • 여러 가지 state를 객체화해서 하나의 state, 함수로 관리할 수 있다.
const [values, setValues] = useState({ title: "", rating: 0, content: "" });

  const handleChange = (e) => {
    const { name, value } = e.target;
    setValues((prevValues) => ({
      ...prevValues,
      [name]: value,
    }));
  };
  • prevValues를 사용하는 이유는 객체 안의 속성이 여러가지일 때 모든 객체가 함께 전달되기 위함이다!

제어 컴포넌트와 비제어 컴포넌트

  • 제어 컴포넌트
    • Controlled Component
    • 인풋의 value값을 리액트에서 지정한다.
    • 리액트에서 사용하는 값과 실제 input 값이 항상 일치해서 주로 권장되는 방법이다.
  • 비제어 컴포넌트
    • Uncontrolled Component
    • 인풋의 value값을 리엑트에서 지정하지 않는다.
    → 리액트에서 사용하는 값과 실제 input 값이 다르다.

파일 인풋

  • 파일 인풋은 비제어로 만들어져야 한다.

ref로 DOM 노드 가져오기

import { useRef } from "react";

function FileInput({ name, value, onChange }) {
  const inputRef = useRef();

  const handleChange = (e) => {
    const nextValue = e.target.files[0];
    onChange(name, nextValue);
  };

  return (
    <input
      type='file'
      onChange={handleChange}
      ref={inputRef}
    />
  );
}

export default FileInput;
  • useRef는 리액트 훅의 한 종류로 특정 DOM 요소에 접근이 가능하다.

사이드 이펙트 정리하기

  • useEffect는 리액트 컴포넌트 함수 안에서 사이드 이팩트를 실행하고 싶을 때 사용하는 함수
  • useEffect는 사이드 이펙트 생성 후 정리하는 방법도 제공한다.
  • 정리 함수를 함께 작성
  useEffect(() => {
    if (!value) return;
    const nextPreview = URL.createObjectURL(value);
    setPreview(nextPreview);

    return () => {
      setPreview();
      URL.revokeObjectURL(nextPreview);
    };
  }, [value]);

데이터 보내기

리액트 Hook

  • 어딘가에 걸 수 있는 고리
  • 리액트에서 use로 시작하는 메소드들을 hook이라고 한다.
  • 내가 작성한 코드를 다른 프로그램에 연결해서 그 값이나 기능을 사용하는 것

리액트 Hook의 규칙

  • 리액트 컴포넌트 혹은 커스텀 함수 안에서만 호출될 수 있다.
  • 리액트 훅은 반복문 안에서 사용될 수 없다
  • 리액트 훅은 렌더링 시 같은 순서대로 사용되어야 한다.

useCallback

  • 함수가 매번 바뀌는 문제를 해결하기 위해 사용
    • 함수 생성 X 리액트에서 함수를 기억할 수 있다
    • useCallback의 디펜던시 리스트 값이 바뀔 때만 함수를 새로 만든

전역 데이터 다루기

  • Context?
    • 프로그램이 커지면 Props와 state만으로 관리하기 힘들다.
  • React Context
    • props를 거치지 않고 쉽게 상태를 전달할 수 있다.
import { createContext, useContext, useState } from "react";

const LocaleContext = createContext();

export function LocaleProvider({ defaultValue = "ko", children }) {
  const [locale, setLocale] = useState(defaultValue);

  return (
    <LocaleContext.Provider value={{ locale, setLocale }}>
      {children}
    </LocaleContext.Provider>
  );
}

export function useLocale() {
  const context = useContext(LocaleContext);

  if (!context) {
    throw new Error("반드시 LocaleProvider 안에서 사용해야 합니다");
  }

  const { locale } = context;

  return locale;
}

export function useSetLocale() {
  const context = useContext(LocaleContext);

  if (!context) {
    throw new Error("반드시 LocaleProvider 안에서 사용해야 합니다");
  }

  const { setLocale } = context;

  return setLocale;
}

상태 관리

  • 데이터를 언제 어디서 바뀐 건지도 파악하기 위해 쉬운 상태 관리 구조 필요
  • ⇒ 데이터의 변경을 한 곳에서 관리 : Flux
  • Flux
  • Redux
  • React Query
  • SWR
  • Recoil