[DAY - 77] useReducer, 사용자정의 hook, 예제 React 변환

2023. 6. 22. 22:34·🔥 부트캠프-웹 개발 🔥/React
  • useReducer
  • 사용자정의 hook
  • 게시판 예제 React 변환

 

1) useReducer

reducer는 여러 state를 관리해야 할 때 주로 사용한다.

사용 문법은 아래와 같다.

const [state, dispatch] = useReducer(reducer, initialState, init);

 

action은 reducer가 state를 참고해서 새로운 state를 만들기 위해 필요하고, reducer는 dispatch 함수에 의해 실행되고 컴포넌트 외부에서 state를 업데이트해 준다.

 

아래는 axios를 이용한 api 로딩, 성공, 실패 예제이다.

 

const initialState = {
    data: [],
    loading: false,
    error: null
}

 

초기값과 타입을 설정해 준다.

 

const reducer = (state, action) => {
    switch (action.type) {
        case "LOADING":
            return {
                data: [],
                loading: true,
                error: null
            }
        case "SUCCESS":
            return {
                data: action.data,
                loading: false,
                error: null
            }
        case "ERROR":
            return {
                data: [],
                loading: false,
                error: action.error
            }
        default:
            return state;
    }
}
const Test2 = () => {
    const [state, dispatch] = useReducer(reducer, initialState);
    const { data, loading, error } = state

    const getData = async () => {
        // 로딩
        dispatch({ type: 'LOADING' })
        try {
            // 성공
            const res = await axios.get('https://jsonplaceholder.typicode.com/posts')
            dispatch({ type: 'SUCCESS', data:res.data })
        }
        catch (error) {
            // 실패
            dispatch({ type: 'ERROR', error : error})
        }
    }

    useEffect(() => {
        getData()
    }, [])

 

reducer에서 action.type이 로딩, 성공, 실패인지 확인을 한 후 state를 return해 준다.

성공 시에 data에 가져온 data를 넣어준다.

 

    return (
        <div>
            {
                data.map(item => <p key={item.id}>{item.id} / {item.title}</p>)
            }
        </div>
    );

 

그 뒤엔 똑같이 가져온 data에 map을 사용해 출력을 해준다.

 

 

2) 사용자정의 hook

같은 원리를 이용해 내가 원하는 hook을 함수 형태로 만들 수 있다.

 

import { useCounter } from '../hooks/useCounter'

const Test3 = () => {
    const { state, onIncre, onDecre, onReset } = useCounter(10)
    return (
        <div>
            <h1>count : {state}</h1>
            <p>
                <button onClick={onIncre}>incre</button>
                <button onClick={onDecre}>decre</button>
                <button onClick={onReset}>reset</button>
            </p>
        </div>
    );
};
export const useCounter = (initialState = 100) => {
    const [state, setState] = useState(initialState)
    const onIncre = () => {
        setState(state + 1)
    }
    const onDecre = () => {
        setState(state - 1)
    }
    const onReset = () => {
        setState(0)
    }
    return { state, onIncre, onDecre, onReset }
};

 

아래 코드는 useCounter함수를 정의한 후 export를 했다.

default로 export 한 게 아니기 때문에 import 할 땐 { } 중괄호로 묶어 주어야 한다.

 

useCounter함수의 초기값은 100이고, state의 초기값은 ussCounter의 초기값으로 넣어주었으므로 똑같이 100이 된다.

하지만 Test3 컴포넌트에서 import 한 뒤 초기값에 10을 넣었으므로 처음 출력 시 10이 출력된다.

 

증가, 감소, 초기화에 대한 함수를 정의하고 return을 해 다른 컴포넌트에서 불러올 수 있게 했다.

 

 

3) 게시판 예제 React 변환

과거 vanilla js로 구현했던 게시판 예제를 useAxios를 만들어 사용해 보았다.

 

import axios from "axios"
import { useEffect, useState } from "react"

export const useAxios = (url = []) => {
    const [data, setData] = useState([])
    const [loading, setLoading] = useState(false)
    const [error, setError] = useState(null)

    useEffect(() => {
        axios.get(url)
            .then(res => {
                setData(res.data)
                setLoading(true)
                setError(null)
            })
            .catch(error => {
                setData([])
                setLoading(false)
                setError('--- ERROR ---')
            })
    }, [url])
    return { data, loading, error }
}

 

api url을 받아 성공 시 data로 넣어주는 hook을 만들었다.

 

    const url = 'https://jsonplaceholder.typicode.com/posts';
    const { data, loading, error } = useAxios(url)
    const [currentPage, setCurrentPage] = useState(1)
    const [postsPerPage, serPostsPerPage] = useState(10)

    const totalPage = data.length;
    const lastPost = currentPage * postsPerPage;
    const firstPost = lastPost - postsPerPage;
    const pageNumber = Math.ceil(totalPage / postsPerPage)
    const currentPosts = data.slice(firstPost, lastPost)

 

기존의 변수들을 선언문과 함께 새로 할당해 주고, 

 

                    <tbody className="table-body">
                        <List currentPosts={currentPosts} loading={loading} />
                    </tbody>
                </table>

                <p className="paging">
                    <Paging pageNumber={pageNumber} setCurrentPage={setCurrentPage} />
                </p>

 

데이터가 출력될 부분들은 컴포넌트로 만들었다.

 

    return (
        <>
            {
                currentPosts.map(item =>
                    <tr key={item.id}>
                        <td>{item.id}</td>
                        <td>{item.title}</td>
                        <td>{item.body}</td>
                    </tr>
                )
            }
        </>
    );

 

table의 tbody 부분

 

    return (
        <>
            {
                pageNum.map((item, idx) =>
                    <a key={idx} href='#' onClick={e => { e.preventDefault(); setCurrentPage(item) }}>{item}</a>
                )
            }
        </>
    );

 

paging 부분

'🔥 부트캠프-웹 개발 🔥/React' 카테고리의 다른 글
  • [DAY - 79] router
  • [DAY - 78] #1 선수 정보 프로젝트
  • [DAY - 76] useMemo, useCallback
  • [DAY - 75] pixabay-api
Yeonhub
Yeonhub
✨ https://github.com/yeonhub 📧 lsy3237@gmail.com
  • Yeonhub
    비 전공자의 Be developer
    Yeonhub
  • 전체
    오늘
    어제
    • 전체보기 (169)
      • 🔍 Tech 🔍 (19)
        • Front-End (11)
        • Back-End (4)
        • AI (1)
        • Server (1)
        • Etc (2)
      • 💡 원티드 프리온보딩 챌린지 💡 (14)
        • PRE-ONBOARDING_AI (11월) (1)
        • PRE-ONBOARDING_FE (2월) (2)
        • PRE-ONBOARDING_FE (1월) (2)
        • PRE-ONBOARDING_FE (12월) (9)
      • 🔥 부트캠프-웹 개발 🔥 (118)
        • HTML5 (7)
        • CSS3 (21)
        • JavaScript (27)
        • JavaScript_advanced (9)
        • React (24)
        • Next (1)
        • MYSql (5)
        • Node (5)
        • 오늘하날(개인프로젝트) (12)
        • 이젠제주투어(팀프로젝트) (7)
      • 💻 CS 💻 (1)
        • 알고리즘 (1)
      • ⚡ 코딩테스트 ⚡ (11)
        • JavaScript (11)
      • 📚 Books 📚 (6)
        • 클린 아키텍처 (2)
        • 인사이드 자바스크립트 (4)
  • 블로그 메뉴

    • 홈
    • 태그
    • 방명록
  • 링크

    • Github
  • 공지사항

  • 인기 글

  • 태그

    프론트엔드 테스트코드
    expo 지도
    node crontab
    node cron
    react vite
    react native admob
    react native bottom sheet
    expo 길찾기
    javascript fcm
    rn admob
    expo fcm
    expo node fcm
    expo deep linking
    expo map
    bottom sheet
    라스콘4
    react native analytics
    node fcm
    expo google map
    Node
    php node
    react native firebase analytics
    react native expo fcm
    rn bottom sheet
    expo fcm push
    expo admob
    node.js fcm
    라스콘
    python node
    컴파운드 컴포넌트 패턴
  • 최근 댓글

  • 최근 글

  • hELLO· Designed By정상우.v4.10.3
Yeonhub
[DAY - 77] useReducer, 사용자정의 hook, 예제 React 변환
상단으로

티스토리툴바