커스텀 훅을 이용한 데이터 페칭
- useProducts.js라는 훅에서 데이터를 받아오는 로직을 처리
- Products.jsx 컴포넌트에서는 그걸 가져와서 화면에 그려주는(UI) 작업
- 기존 파일 : Products.jsx(하단 코드)을 활용해 useProducts.js / Products.jsx로 나누기
import React, { useEffect, useState } from "react";
export default function Products() {
const [loading, setLoading] = useState(false)
const [checked, setChecked] = useState(false)
const [error, setError] = useState()
const [products, setProducts] = useState([])
const handleChange = () => setChecked((prev) => !prev)
useEffect(() => {
setLoading(true)
setError(undefined)
fetch(`data/${checked ? "sale_" : ""}products.json`)
.then((res) => res.json())
.then((data) => {
console.log("네트워크에서 데이터를 잘 불러옴")
setProducts(data)
})
.catch((e) => setError("에러가 발생함!"))
.finally(() => setLoading(false))
return () => {
console.log("데이터 처리 완료")
}
}, [checked])
if(loading) return <p>Loading 중...</p>
if(error) return <p>{error}</p>
return (
<>
<input id="checkbox" type="checkbox" checked={checked} value={checked} onChange={handleChange}/>
<label htmlFor="checkbox">세일상품보기</label>
<ul>
{products.map((products) => (
<li key={products.id}>
<article>
<h3>{products.name}</h3>
<p>{products.price}</p>
</article>
</li>
))}
</ul>
</>
)
}
useProducts.js
import {useState, useEffect} from "react";
//데이터 로직 담당
export default function useProducts({ salesOnly }) {
// useEffect를 가져다 프로덕트훅에 사용
const [loading, setLoading] = useState(false)
// 에러 여부
const [error, setError] = useState()
// 빈배열
const [products, setProducts] = useState([])
useEffect(() => {
// false인 로딩을 true로 바꿈
setLoading(true)
// 에러는 아무것도 들어가있지 않음
setError(undefined)
fetch(`data/${salesOnly ? "sale_" : ""}products.json`)
.then((res) => res.json())
.then((data) => {
console.log("네트워크에서 데이터를 잘 불러옴")
setProducts(data)
})
.catch((e) => setError("에러가 발생함!"))
.finally(() => setLoading(false))
return () => {
console.log("데이터 처리 완료")
}
}, [salesOnly])
return {loading, error, products }
}
Products.jsx
import React, { useState } from "react";
import useProducts from "../src/hooks/useProducts";
// 화면 ui 담당
export default function Products() {
const [checked, setChecked] = useState(false)
const { loading, error, products } = useProducts({ salesOnly: checked })
const handleChange = () => setChecked((prev) => !prev)
// 로딩, 에러 처리
if (loading) return <p>Loading 중...</p>;
if (error) return <p>{error}</p>;
return (
<>
<input id="checkbox" type="checkbox" checked={checked} value={checked} onChange={handleChange}/>
<label htmlFor="checkbox">세일상품보기</label>
<ul>
{products.map((product) => (
<li key={product.id}>
<article>
<h3>{product.name}</h3>
<p>{product.price}</p>
</article>
</li>
))}
</ul>
</>
)
}
React Developer Tools
- 리액트를 사용하는지 확인할 수 있는 확장 프로그램
- 컴포넌트 트리 보기
- Props 확인
- State 확인
- Hooks 확인
- Context 확인
- 컴포넌트가 다시 렌더링되는 이유 분석 가능
- React Developer Tools => 크롬 확장 프로그램 다운
- 리액트를 사용한 사이트와 사용하지 않은 사이트로 볼 수 있음(흑백 : 사용X / 컬러 : 사용O)
- f12 => components, profiler가 새로 생김
Elements 탭 VS Component 탭
Elements 탭 |
Component 탭 |
|
| 확인 | 실제 HTML DOM | React 컴포넌트 |
| 주요 내용 | CSS, HTML... | Props, State, Hooks... |
| 목적 | 화면/스타일 분석 | React 데이터 흐름 분석 |
useReducer
- 상태 변경 종류가 여러 개일 대 상태 변경 규칙을 하나의 함수로 관리하는 Hok 함수
- 기본 구조:
- const [state, dispatch] = useReducer(reducer, initialState)
- dispatch : 상태 변경 요청을 보내는 함수
- reducer : 상태를 어떤 방식으로 변경할지 정의한 함수
- initialStatev: 처음 사용할 초기 상태
useReducer의 전체 흐름
- 사용자가 버튼 클릭 -> dispatch 실행 -> action 객체 전달 -> reducer
- 새로운 상태 반환 -> React가 상태 저장 -> 컴포넌트 재랜더링
useCallback
- 함수 자체를 기억하는 Hook
- React 함수형 컴포넌트는 랜더링 될 때마다 함수 전체가 다시 실행됨
- 따라서 컴포넌트 내부의 함수도 다시 만들어지게 됨
- ex)
function App() {
const handleAdd = () => {
console.log("추가")
}
}
=> 일때 App이 다시 랜더링되면 새로운 handleAdd 함수 객체가 만들어짐
(이전 handleAdd !== 새로운 handleAdd)
useMemo
- 값을 감싸는 Hook
- 계산 비용이 실제로 크고, 랜더링이 자주 발생하는 곳에 사용
- 함수가 아니라 계산된 결과값을 기억
- ex)
const 기억된값 = useMemo(() => {
return 계산결과
}, [의존성])
=> [의존성]이 변경될 때 새로 계산되고, 의존성이 바뀌지 않다면 이전 결과를 기억해서 리턴함