본문 바로가기

프론트앤드 수업

[React] Sqlite DB사용, 간단한 웹페이지 만들기_2

728x90

Client에서 값을 받아오기에 앞서 받아온값의 상태를 확인하기위해 Reducer를 사용,처음 실핼될때 한번만 사용하기위해 Effect로 실행시키는 함수를 다른 파일에 작성하였다.

useAsync.js

import { useReducer, useEffect } from "react";
const initialState = {
    loading: false,
    data: null,
    error: null
}
// 로딩중, 데이터 받기 성공, 데이터 받기 실패 
// LOADING , SUCCESS,  ERROR
function reducer(state, action){
    switch(action.type){
        case "LOADING":
        return {
            loading: true,
            data: null,
            error: null
        };
        case "SUCCESS":
        return {
            loading: false,
            data: action.data, // 실행될때 받아온 값을 넣어줌
            error: null
        };
        case "ERROR":
        return {
            loading: false,
            data: null,
            error: action.error
        };
        default:
        return state;
    }
}
function useAsync(callback, deps=[]){
    const [state, dispatch] = useReducer(reducer, initialState);
    const fetchDate = async () => {
        dispatch({type:"LOADING"});
        try {
            const data = await callback();
            dispatch({
                type: "SUCCESS",
                data: data
            })
        }
        catch(e){
            dispatch({
                type:"ERROR",
                error: e
            })
        }
    }
    useEffect(()=>{
        fetchDate();
        // eslint-disable-next-line
    }, deps);
    return [state, fetchDate];
}
export default useAsync

첫 홈 메인화면, 슬라이더는 ant.design 에서 필요한 코드를 뺴와 만들었음.
https://ant.design/components/carousel/

main / index.js

async function getProducts(){ // 서버에서 products로 요청하면 주는 값들을 가져와서 리턴해준다.
    const response = await axios.get(`${API_URL}/products`)
    return response.data;
}
const contentStyle = {
    height: '160px',
    color: '#fff',
    lineHeight: '160px',
    textAlign: 'center',
    position:'absolute',
    bottom : '50px',
  };

const MainPage = () => {
    const onChange = (currentSlide) => {
        console.log(currentSlide);
      };
            // eslint-disable-next-line
    const [state, refetch] = useAsync(getProducts,[]) // 값을 요청한다. useAsync파일에 있는 함수를 실행 1회만 실행을위해 빈배열을 넣어준다.
    const { loading, data, error} = state;
    if(loading) return <div>로딩중......</div>
    if(error) return <div>에러가 발생했습니다.</div>
    if(!data) return <div>로딩중입니다.</div>
    return (
        <div>
            <div id="main">
                <div id="banner">
                  {/* 메인 슬라이더 */}
                    <Carousel afterChange={onChange} autoplay>
      <div>
      <img src="images/banners/banner1.png" alt="" /> 
        <h3 style={contentStyle}></h3>
      </div>
      <div>
      <img src="images/banners/banner1.png" alt="" />
        <h3 style={contentStyle}></h3>
      </div>
      <div>
      <img src="images/banners/banner1.png" alt="" />
        <h3 style={contentStyle}></h3>
      </div>
    </Carousel>
                  {/* 메인 슬라이더 / */}
                </div>
                <div id="product-list" className='inner'>
                    <h2>그린조명 최신상품</h2>
                    <div id="product-items">
                        {data.map(product=><MainProduct key={product.id} product={product}/>)}
                    </div>
                </div>
            </div>
        </div>
    );
};
const MainProduct = ({product}) => {
    return (
        <div className="product-card">
            <Link to={`/product/${product.id}`}> // 클릭이벤트 삽입.
            <div className='product-img'>
                <img src={product.imageUrl} alt="" />
            </div>
            <div className='product-contents'>
                <span className='product-name'>{product.name}</span>

                <span className='product-price'>{product.price}</span>
                <div className='product-seller'>
                    <img src="images/icons/avatar.png" alt="" />{product.seller}
                </div>
            </div>
            </Link>
        </div>
    );
};

맵으로 돌려 값들을 모두 받아와 map으로 돌리고, Link to를 이용해 하나하나 상세페이지보기 클릭이벤트를 걸어준다.

728x90
댓글