-
리액트로 데이터 다루기코드잇 부스트 2024. 8. 5. 18:23
리액트로 데이터 다루기
배열 렌더링하기
- mock 데이터 추가하기
- json파일을 생성해주고 이를 js 파일에서 import 하여 사용할 수 있다.
- mock 데이터는 네트워크로 받아온 데이터를 흉내내는 파일이다.
- map으로 배열 렌더링하기
- map 메소드 안에서 jsx를 리턴하면 jsx를 여러개 추가한 것처럼 동작한다.
- sort로 정렬 바꾸기
- items.sort( (a,b) => b.rating - a.rating ) items.sort( (a,b) => b[rating] - a[rating] )
- sort 함수를 이용하여 mock 데이터를 정렬 시킨 뒤 렌더링 할 수 있다.
- filter로 아이템 삭제하기
- app.js에서 handleDelete함수를 정의하여 ReviewListItem의 Prop으로 보낸다.
- 그 뒤 ReviewListItem에서 id를 onDelete함수의 prop으로 보내주고,
- app에서 이를 filter함수로 제거한 item목록을 만들어 다시 ReviewListItem에게 보내준다.
- 배열을 렌더링할 땐 key를 기억하세요
- 배열의 인덱스는 배열의 순서대로 지정되기 때문에 배열의 요소가 삭제되어 순서가 바뀌면,
- 배열이 가지고 있던 데이터는(ex: input값) 인덱스에 종속되기 때문에 엉뚱한 위치에 렌더링 될 수 있다.
- 배열을 렌더링 할 땐 태그에 key 속성을 지정해서 고유하게 만들어주어야 한다.
React로 데이터 다루기
- 리액트에서 fetch 사용하기
async함수와 await를 사용한다.export async function getReviews() { const response = await fetch('<https://learn.codeit.kr/api/film-reviews>'); const body = await response.json(); return body; }
- useEffect로 초기데이터 가져오기
- useEffect로 fetch하는 부분을 묶으면 초기 렌더링할 때만 데이터를 요청하여 불러온다.
- 서버에서 정렬한 데이터 받아오기
데이터를 받은 뒤 정렬해서 보여주는 것이 아닌 query를 통해 정렬된 데이터를 요청할 수 있다.export async function getReviews(order = 'createdAt') { const query = `order=${order}`; const response = await fetch( `https://learn.codeit.kr/api/film-reviews?${query}` ); const body = await response.json(); return body; }
- 이는 서버에서 정의가 되어있어야 한다.
- const handleLoad = async (orderQuery) => { const { reviews } = await getReviews(orderQuery); setItems(reviews); };
- 페이지네이션이란?
- 데이터가 많을 때 이를 나눠서 보여주는 것을 페이지네이션이라고 한다.
- offset:
- 데이터가 바뀌게 될 경우 중복 데이터를 보여준다거나 누락시킬 수 있다.커서가 가르키는 데이터를 기준으로 페이지를 나눈다.
- 백엔드 구현이 어렵다.
- 커서 기반 페이지네이션:
- 받아온 갯수를 기반으로 페이지를 나눈다.
- 데이터 더 불러오기
offset을 이용한 페이지네이션 구현.export async function getReviews({ order = 'createdAt', offset = 0, limit = 6, }) { const query = `order=${order}&offset=${offset}&limit=${limit}`; const response = await fetch( `https://learn.codeit.kr/api/film-reviews?${query}` ); const body = await response.json(); return body; }
- 조건부 연산자
- {조건문 && jsx}
- 위 문법으로 조건문이 참 일 때만 rendering을 진행하게 할 수 있다.
- 비동기로 State를 변경할 때 주의할 점
- 기존 방식인 비동기로 State를 변경하면 잘못된 시점의 값을 사용하는 문제가 생길 수 있다.
- 이를 해결하려면 콜백에서 이전 State를 불러와서 사용하면 된다.
- //기존 setItems([...items, ...reviews]); //개선 setItems((prevItems) => [...prevItems, ...reviews]);
- useState 뽀개기
- 콜백으로 초깃 값 지정콜백으로 State 변경
- const [count, setCount] = useState(0); const handleAddClick = async () => { await addCount(); setCount((prevCount) => prevCount + 1); }
- const [state, setState] = useState(() => { // 초기값을 계산 return initialState; });
- 네트워크 로딩 처리하기
- 데이터를 불러오는 과정에서 불필요하게 여러번 요청을 보내는 경우가 생길 수 있음.
- 이를 Loading 처리로 해결함.
입력 폼 다루기
import { useState } from 'react'; import './ReviewForm.css'; function ReviewForm() { const [title, setTitle] = useState(''); const [rating, setRating] = useState(0); const [content, setContent] = useState(''); const handleTitleChange = (e) => { setTitle(e.target.value); }; const handleRatingChange = (e) => { const nextRating = Number(e.target.value); setRating(nextRating); }; const handleContentChange = (e) => { setContent(e.target.value); }; return ( <form className="ReviewForm"> <input value={title} onChange={handleTitleChange} /> <input type="number" value={rating} onChange={handleRatingChange} /> <textarea value={content} onChange={handleContentChange} /> </form> ); } export default ReviewForm;
- 리액트의 입력폼
- input태그의 value 속성을 state에 저장하고, onChange를 핸들링하여 state를 업데이트 시킨다.
- onChange는 요소의 값이 수정되면 발생하는 이벤트이다.
const handleSubmit = (e) => { e.preventDefault(); console.log({ title, rating, content, }); }; return ( <form className="ReviewForm" onSubmit={handleSubmit}> <input value={title} onChange={handleTitleChange} /> <input type="number" value={rating} onChange={handleRatingChange} /> <textarea value={content} onChange={handleContentChange} /> <button type="submit">확인</button> </form> ); }
- onSubmit을 써보자
- handleSubmit 함수를 만들어 submit 시 호출될 함수를 정의한다. handleSubmit에서 event.preventDefault()를 호출해 페이지 새로고침을 방지해야 한다.
function ReviewForm() { const [values, setValues] = useState({ title: '', rating: 0, content: '', }); const handleChange = (e) => { const { name, value } = e.target; setValues((prevValues) => ({ ...prevValues, [name]: value, })); }; const handleSubmit = (e) => { e.preventDefault(); console.log(values); }; return ( <form className="ReviewForm" onSubmit={handleSubmit}> <input name="title" value={values.title} onChange={handleChange} /> <input type="number" name="rating" value={values.rating} onChange={handleChange} /> <textarea name="content" value={values.content} onChange={handleChange} /> <button type="submit">확인</button> </form> ); }
- 하나의 state로 폼 구현하기
- 각 이벤트 객체에서 name값을 가져올 수 있다.
- 이를 이용하면 하나의 state로 전부 관리 할 수 있다.
- 제어 컴포넌트와 비제어 컴포넌트
- state로 값을 받고, 그를 value에 반영시키는 것으로 state와 input의 값을 일치 시킬 경우 제어 컴포넌트라고 함. (권장)
- 일치하지 않는 경우엔 비제어 컴포넌트라고 함.
- 파일 인풋
- 파일input은 보안을 위해 비제어 컴포넌트로 만들어야 한다.
- ref로 DOM 노드 가져오기
- react에서 useRef는 일반적으로 특정 DOM을 선택하는 요소를 말한다.
- 파일 인풋 초기화
- 파일의 value는 사용자만 바꿀 수 있고, 자바스크립트로는 빈 문자열로만 바꿀 수 있다.
- 즉, 빈 문자열로 바꿔주면 초기화된다.
- 이미지 파일 미리보기
- URL.createObjectURL(이미지파일)
- 위 코드로 이미지 파일을 주소로 만들어 img 태그에 사용할 수 있음
- 주소를 만들 때마다 웹 브라우저의 메모리를 할당함.
useEffect(() => { if (!value) return; const nextPreview = URL.createObjectURL(value); setPreview(nextPreview); return () => { setPreview(); URL.revokeObjectURL(nextPreview); }; }, [value]);
- 사이드 이펙트 정리하기
- createObjectURL은 웹 브라우저의 메모리를 할당하고 이를 사이드 이펙트라고 함.
- 위 코드처럼 URL.revokeObjectURL로 정리할 수 있음.
데이터 보내기
- 글 작성하기
- FormData()를 body로 사용해서 POST 메소드로 데이터를 보낼 수 있다.
- 리스폰스 데이터 반영하기
- POST의 리스폰스로 오는 데이터를 기존 데이터에 추가해주는 코드를 작성해주면 해결할 수 있다.
- POST 이후 새로고침을 하지 않으면 데이터가 반영되지 않는 오류가 있다.
- 글 수정하기
- put 메소드를 사용해서 수정할 수 있다.
- 글 삭제하기
- delete 메소드로 글을 삭제할 수 있다.
- 리액트 Hook
- useSatet:
- 변수처럼 값을 사용하는 Hook입니다. useState 생성한 state는 컴포넌트 안에 있는 값이 아니라 리액트가 따로 관리하는 값입니다.
- useEffect:
- useEffect는 내 콜백 함수를 리액트에 연결하고, 렌더링 이후에 함수를 실행하는 Hook입니다.
- useRef:
- useRef는 리액트가 관리하는 Ref 객체에 연결해서 current같은 값을 사용할 수 있게 해주는 Hook입니다.
- useSatet:
- 리액트 Hook의 규칙
- 리액트 Hook은 반드시 함수형 컴포넌트나 커스텀 Hook 함수 안에서 실행되어야 한다.
- 리액트 Hook은 반드시 함수의 최상위에서 실행해야 합니다. 즉, 중첩된 함수, 반복문 또는 조건문 안에서 호출하면 안된다.(Hook을 호출할 때는 항상 동일한 순서로 Hook을 호출해야 하기 때문.)
- 커스텀 Hook을 포함해서, 이름은 항상 "use"로 시작해야 한다.
- Hook은 state나 side effect를 관리하기 위해 사용해야 한다.
- useCallback
- useCallback(): 콜백 함수를 캐싱하고 재사용하기 위해 사용됨
- useCallback(): dependency array가 변경될 때만 콜백 함수를 생성.
- useCallback()은 주로 자식 컴포넌트에 props로 전달되는 콜백 함수를 최적화하는데 사용됨..
- const memoizedCallback = useCallback( () => { // contents }, [/* dependency array */], );
전역 데이터 다루기
- Context란?
- Context는 프롭 드릴링을 해결하기 위해 사용하는 기능이다.
- 이때 컴포넌트의 단계가 많다면 여러 번 반복해서 Prop을 내려줘야 한다. (프롭 드릴링(Prop Drilling))
- Context로 데이터 내려주기
- // contexts/LocaleContext.js import { createContext } from "react"; const LocaleContext = createContext(); export default LocaleContext; // components/App.js import LocaleContext from "../contexts/LocaleContext"; ... function App() { ... return ( <LocaleContext.Provider value="ko">... </LocaleContext.Provider>); } // components/ReviewList.js import LocaleContext from "../contexts/LocaleContext"; function ReviewListItem({ item, onDelete, onEdit }) { const locale = useContext(LocaleContext); ... return ( ... <p>현재 언어: {locale}</p>... ); }
- Context 값에 State 사용하기
- function LocaleSelect({ value, onChange }) { const handleChange = (e) => onChange(e.target.value); return ( <select value={value} onChange={handleChange}><option value="ko">한국어</option><option value="en">English</option></select>); } export default LocaleSelect;
- Context 코드 분리하기
- State를 컴포넌트 외부에서 관리하여, 상태 변경에 따른 리렌더링이 불필요한 컴포넌트에서 발생하지 않는다.
- 상태를 컴포넌트 외부에서 관리하면, 다른 컴포넌트에서도 해당 상태에 접근할 수 있으므로, 코드의 중복을 줄일 수 있다.
- 언어 설정과 관련된 상태는 애플리케이션 전역에서 사용되므로, 이를 하나의 중앙화된 장소에서 관리할 수 있어서 유지보수가 용이하다.
- Locale Context에서 상태를 관리하는 것의 이점:
유용한 실습
https://www.codeit.kr/topics/handling-data-with-react/lessons/5054
'코드잇 부스트' 카테고리의 다른 글
GIt (0) 2024.08.05 실용적 유닉스 커맨드 (0) 2024.08.05 React 웹 개발 시작하기 (0) 2024.07.13 쿠키, 세션, 스토리지, 로컬 스토리지 이해하기 (0) 2024.07.13 자바스크립트 웹 개발 기본기 (0) 2024.07.13 - mock 데이터 추가하기