[DAY - 73] 회원 관리 예제, 장바구니 예제, JS 예제 React 변환

2023. 6. 16. 22:11·🔥 부트캠프-웹 개발 🔥/React
  • 회원 관리 예제
  • 장바구니 예제
  • JS 예제 React 변환

 

1) 회원관리 예제

회원관리 예제

 

React를 이용해 회원 추가, 삭제, 수정 기능을 구현해 보았다.

 

import React, { useEffect, useRef } from 'react';
import { useState } from 'react';
import AddUser from './AddUser';
import EditUser from './EditUser';
import ListUser from './ListUser';
import Message from './Message';

const dataList = [
    { id: 1, name: '김', addr: '서울특별시' },
    { id: 2, name: '이', addr: '부산광역시' },
    { id: 3, name: '박', addr: '경기도 수원시' },
    { id: 4, name: '최', addr: '강원도 태백시' },
    { id: 5, name: '윤', addr: '경기도 성남시' },
]

const Customer = () => {
    // localStorage.clear();
    const [data, setData] = useState(
        () => JSON.parse(localStorage.getItem('data')) || dataList
    );
    const no = useRef(data.length + 1)
    const [isShow, setIsShow] = useState(false)
    const [edit, setEdit] = useState({})
    const [isMsg, setIsMsg] = useState(false)
    const [msg, setMsg] = useState('')

    useEffect(() => {
        localStorage.setItem('data', JSON.stringify(data))
    }, [data])

    const onEdit = (item) => {
        setIsShow(true)
        setEdit(item)
    }
    const onDel = id => {
        setData(data.filter(item => item.id !== id))
    }
    const onAdd = user => {
        user.id = no.current++
        setData([
            ...data,
            user
        ])
        setIsMsg(true)
        setMsg('추가 완료')
    }
    const onUpdate = (user) => {
        setData(data.map(item => item.id === user.id ? user : item))
    }
    return (
        <div className='Customer'>
            {
                isShow ? <EditUser edit={edit} setIsShow={setIsShow} onUpdate={onUpdate} /> : <AddUser onAdd={onAdd} />
            }
            <Message msg={msg} isMsg={isMsg} setIsMsg={setIsMsg}/>

            <ListUser data={data} onDel={onDel} onEdit={onEdit} />
        </div>
    );
};

export default Customer;

 

회원 수정

import React, { useRef, useState } from 'react';

const AddUser = ({ onAdd }) => {
    const nameRef = useRef()

    const [user, setUser] = useState(
        { name: '', addr: '' }
    )
    const { name, addr } = user
    const changeInput = e => {
        const { name, value } = e.target
        setUser(
            {
                ...user,
                [name]: value
            }
        )
    }
    const onSubmit = e => {
        e.preventDefault()
        if (!name || !addr) return
        onAdd(user)
        setUser(
            {
                name: '',
                addr: ''
            }
        )
        nameRef.current.focus()
    }
    return (
        <form onSubmit={onSubmit}>
            <h2>회원 추가</h2>
            <p>
                <label>이름</label>
                <input type="text" value={name} name="name" onChange={changeInput} ref={nameRef} />
            </p>
            <p>
                <label>주소</label>
                <input type="text" value={addr} name="addr" onChange={changeInput} />
            </p>
            <p>
                <button type='submit'>회원추가</button>
            </p>
        </form>
    );
};

export default AddUser;

 

회원 수정 버튼을 누르게 되면 해당 data를 edit input창에 보내주게 되는데 수정 화면에서 다른 회원의 수정 버튼을 누르면 나오지 않는다.

이때 사용해야 하는 것이 지난 시간에 배운 useEffect이다.

javascript에서 변수에 새로운 값이 할당될 때마다 재선언/재할당 해주는 것이랑 비슷하다.

따라서 edit값이 바뀔 때마다 useEffect로 인해 새로운 회원의 정보가 수정칸에 입력된다.

 

 

2) 장바구니 예제

장바구니 예제

import { useRef, useState } from 'react';
import CartForm from './CartForm';
import CartList from './CartList';

const Cart = () => {
    const [data, setData] = useState([])
    const [isEdit, setIsEdit] = useState(false)
    const no = useRef(1)
    const textRef = useRef('')

    const [cart, setCart] = useState(
        { text: '', price: '', amount: '' }
    )
    const changeInput = e => {
        const { name, value } = e.target
        setCart(
            { ...cart, [name]: value }
        )
    }
    const onSubmit = e => {
        e.preventDefault()
        if (!cart.text && cart.amount < 1) return
        if (isEdit) {
            cart.total = Number(cart.price * cart.amount)
            const newData = data.map(item => item.id === cart.id ? { ...item, ...cart } : item)
            setData(newData)
            setCart(
                { text: '', price: '', amount: '' }
            )
            setIsEdit(false)
            textRef.current.focus()
        } else {
            cart.id = no.current++
            cart.total = Number(cart.price * cart.amount)
            setData(
                [...data, cart]
            )
            setCart(
                { text: '', price: '', amount: '' }
            )
            textRef.current.focus()
        }
    }
    const onDel = id => {
        setData(data.filter(item => item.id !== id))
    }
    const onDelAll = () => {
        setData([])
    }
    const onEdit = (item) => {
        setIsEdit(true)
        setCart(item)
    }
    return (
        <>
            <div className="con-box">
                <CartForm cart={cart} onSubmit={onSubmit} changeInput={changeInput} isEdit={isEdit} textRef={textRef} />
                <CartList data={data} onDel={onDel} onDelAll={onDelAll} onEdit={onEdit} />
            </div>
        </>
    );
};

export default Cart;

 

이번 예제에서 새로 배운 내용은 총금액에 해당하는 cart.total이다.

 

    const onSubmit = e => {
        e.preventDefault()
        if (!cart.text && cart.amount < 1) return
        if (isEdit) {
            cart.total = Number(cart.price * cart.amount)
            const newData = data.map(item => item.id === cart.id ? { ...item, ...cart } : item)
            setData(newData)
            setCart(
                { text: '', price: '', amount: '' }
            )
            setIsEdit(false)
            textRef.current.focus()
        } else {
            cart.id = no.current++
            cart.total = Number(cart.price * cart.amount)
            setData(
                [...data, cart]
            )
            setCart(
                { text: '', price: '', amount: '' }
            )
            textRef.current.focus()
        }
    }

 

form에서 submit을 할 때 price와 amount를 곱해서 나온 값을 숫자 형태로 변환(Number)하고 total에 넣어 주었다.

 

import CartItem from "./CartItem";

const CartList = ({ data, onDel, onDelAll, onEdit }) => {
    return (
        <div className="con2">
            <p>
                <button className="btn" onClick={onDelAll}>전체삭제</button>
                <span className="total">
                    총금액 :  {
                        data.reduce((acc, curr) => {
                            return acc + curr.total
                        }, 0).toLocaleString()
                    }
                </span>
            </p>
            <ul className="list">
                {
                    data.map(item => <CartItem key={item.id} item={item} onDel={onDel} onEdit={onEdit} />)
                }

            </ul>
        </div>
    );
};

export default CartList;

 

총금액의 경우 data객체의 total값을 다 더해야 하므로 reduce를 사용했다.

시작값은 0부터 누적해서 더하게 된다.

 

 

3) JS 예제 React로 변환

북카페 예제

 

javascript로 만들었던 예제를 React로 변환해 보았다.

 

import React, { useRef, useState, useEffect } from 'react';
import './Basket.scss'
import '../assets/css/reset.css'
import BasketAdd from './BasketAdd';
import BasketList from './BasketList';



const Basket = () => {
    const [data, setData] = useState([])
    const titleRef = useRef('')
    const [book, setBook] = useState(
        { title: '', author: '', bookcode: '' }
    )
    const no = useRef(1)
    const [isMsg, setIsMsg] = useState(false)
    const [isAddDel, setIsAddDel] = useState(false)
    const [msg, setMsg] = useState('')

    const onSubmit = (e) => {
        e.preventDefault()
        if (!book.title || !book.author || !book.bookcode) {
            setIsMsg(true)
            setIsAddDel(false)
            setMsg('값을 입력하세요')
        } else {

            book.id = no.current++
            setData(
                [...data, book]
            )
            setBook(
                { title: '', author: '', bookcode: '' }
            )
            setIsMsg(true)
            setIsAddDel(true)
            setMsg('도서 추가 완료')
            titleRef.current.focus()
        }
    }
    const changeInput = (e) => {
        const { name, value } = e.target
        setBook(
            { ...book, [name]: value }
        )
    }
    const onDel = (id) => {
        setData(data.filter(item => item.id !== id))
        setIsMsg(true)
        setIsAddDel(true)
        setMsg('도서 삭제 완료')
    }
    useEffect(() => {
        const timer = setTimeout(() => {
            setIsMsg(false)
            setIsAddDel(false)
        }, 2000);
        return () => {
            clearTimeout(timer)
        }
    }, [isMsg])
    return (
        <div>
            <section className='main-book'>
                <h2>북카페 도서 관리</h2>
                <div className="inner">
                    <div className="book-input">
                        <BasketAdd onSubmit={onSubmit} book={book} changeInput={changeInput} titleRef={titleRef} />
                    </div>
                    <div className="book-list">
                        <BasketList data={data} onDel={onDel} />
                    </div>
                </div>
                {
                    isMsg ? <div className={`show ${isAddDel ? 'on' : 'off'}`}> {msg} </div> : <div></div>
                }
            </section>
        </div>
    );
};

export default Basket;

메세지

 

javascript로 만든 예제를 React로 구현할 때 어려웠던 부분은 연산자 제약이다.

비교적 적은 연산자만 사용 가능하기 때문에 '도서 추가 완료', '도서 삭제 완료', '값을 입력하세요' 총 3가지 메시지를 출력하기 위해 삼항연산자와 상태변수를 두 개 사용했다.

 

{
    isMsg ? <div className={`show ${isAddDel ? 'on' : 'off'}`}> {msg} </div> : <div></div>
}

 

추가, 삭제, 값 미입력시 기본적으로 isMsg는 true가 되어야 하고, 추가와 삭제는 같은 on class를 사용하므로 isAddDel을 이용해 구별했다.

마지막으로 값 미입력시 나오는 메시지는 off 클래스를 붙여주기 위해 isMsg === true && isAddDel === false를 조건으로 만들어 주었다.

 

    useEffect(() => {
        const timer = setTimeout(() => {
            setIsMsg(false)
            setIsAddDel(false)
        }, 2000);
        return () => {
            clearTimeout(timer)
        }
    }, [isMsg])

 

마지막으로 메시지를 2초 보여주기 위해서 isMsg의 상태가 변할 때 setTimeout이 실행되도록 구현했다.

'🔥 부트캠프-웹 개발 🔥/React' 카테고리의 다른 글
  • [DAY - 75] pixabay-api
  • [DAY - 74] bootstrap, material, styled
  • [DAY - 72] checkbox, useEffect
  • [DAY - 71] 탭 메뉴(class, 상태변수)
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 deep linking
    expo fcm push
    프론트엔드 테스트코드
    react native expo fcm
    expo admob
    expo node fcm
    react vite
    react native analytics
    expo google map
    rn bottom sheet
    javascript fcm
    expo 길찾기
    react native admob
    node crontab
    node cron
    bottom sheet
    Node
    expo 지도
    컴파운드 컴포넌트 패턴
    node.js fcm
    라스콘4
    rn admob
    react native bottom sheet
    라스콘
    expo map
    php node
    python node
    react native firebase analytics
    expo fcm
    node fcm
  • 최근 댓글

  • 최근 글

  • hELLO· Designed By정상우.v4.10.3
Yeonhub
[DAY - 73] 회원 관리 예제, 장바구니 예제, JS 예제 React 변환
상단으로

티스토리툴바