리액트로 데이터 다루기
배열 렌더링하기
배열을 렌더링할 땐 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값을 리엑트에서 지정하지 않는다.
파일 인풋
- 파일 인풋은 비제어로 만들어져야 한다.
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
'TIL' 카테고리의 다른 글
웹 프로토콜 (0) | 2024.08.15 |
---|---|
함수형 프로그래밍 (Function Programming) (0) | 2024.08.14 |
http와 https의 통신 방법 차이 (0) | 2024.08.13 |
브라우저의 렌더링 과정 (0) | 2024.08.12 |
[PB] 7주차 스터디 정리 (0) | 2024.08.06 |