ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • 리액트로 데이터 다루기
    코드잇 부스트 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 사용하기
      export async function getReviews() {
      	const response = await fetch('<https://learn.codeit.kr/api/film-reviews>');
      	const body = await response.json();
      	return body;
      }
      
       async함수와 await를 사용한다.
    • useEffect로 초기데이터 가져오기
      • useEffect로 fetch하는 부분을 묶으면 초기 렌더링할 때만 데이터를 요청하여 불러온다.
    • 서버에서 정렬한 데이터 받아오기
      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;
      }
      
      데이터를 받은 뒤 정렬해서 보여주는 것이 아닌 query를 통해 정렬된 데이터를 요청할 수 있다.
      • 이는 서버에서 정의가 되어있어야 한다.
      • const handleLoad = async (orderQuery) => { const { reviews } = await getReviews(orderQuery); setItems(reviews); };
    • 페이지네이션이란?
      • 데이터가 많을 때 이를 나눠서 보여주는 것을 페이지네이션이라고 한다.
      • 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;
      }
      
      
      offset을 이용한 페이지네이션 구현.
    • 조건부 연산자
      • {조건문 && 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입니다.
    • 리액트 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 코드 분리하기
      1. State를 컴포넌트 외부에서 관리하여, 상태 변경에 따른 리렌더링이 불필요한 컴포넌트에서 발생하지 않는다.
      2. 상태를 컴포넌트 외부에서 관리하면, 다른 컴포넌트에서도 해당 상태에 접근할 수 있으므로, 코드의 중복을 줄일 수 있다.
      3. 언어 설정과 관련된 상태는 애플리케이션 전역에서 사용되므로, 이를 하나의 중앙화된 장소에서 관리할 수 있어서 유지보수가 용이하다.
    • 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
Designed by Tistory.