본문 바로가기
💻CODING/react. vue

[react] 리액트 테이블 게시판 만들기 ver.1 (axios, useEffect, 글삭제)

by 코딩하는 갓디노 2021. 4. 13.

react 테이블 게시판 구현하기

 

구현내용
· npm package: creat-react-app
· css 라이브러리: tailwind
· axios를 통한 서버 통신
· 테이블 형식의 게시판 구현 
· 데이터 추가/수정/삭제 기능 추가
· 모달 팝업창 오픈

 

구현 화면

 

 

프로젝트 폴더 설치

npm 패키지 설정

npm create react-app 폴더이름 //폴더 생성
cd 폴더이름 //해당 폴더로 접근
npm start //local 서버 띄우기

 

처음에 어설픈 기억력으로 npm install create-react-app으로 계속 입력하다가 시간을 버린 기억이 있습니다. ㅠㅜ
구글링하면 될 것을….
아무튼 npm start 로 local 서버를 띄웁니다.

 

tailwind 설치 

tailwind를 설치하여 간편하게 css를 적용하겠습니다. 
혹시 번거로워 설치를 원치 않을 경우,  css는 각자의 스타일에 맞게 적용하시면 됩니다. 

tailwind를 사용하는 방법은 tag 안의 className에 style 이름을 주면 되기 때문에
사용 방법이 매우 간편하고, 커스터마이징하기에 그 어떤 라이브러리보다 빠르고 쉽습니다. 

<div className='스타일 이름'>hello</div>

 

아래의 Tailwind 공식문서 가이드에 맞게 설치합니다.

https://tailwindcss.com/docs/guides/create-react-app

 

Install Tailwind CSS with Create React App - Tailwind CSS

Setting up Tailwind CSS in a Create React App project.

tailwindcss.com

이제 스타일 라이브러리 설치까지 준비가 다 완료되었습니다.

 

폴더 구조

Board.js > Tr.js > Td.js (테이블 구조)
Board.js > Post.js (폼)
Board.js > Modal.js (모달창)

 

axios 서버 통신으로 더미 데이터 get

npm install axios

 

jsonplaceholder라는 free online REST API 사이트로부터 10명의 user 더미 데이터로 가져옵니다. 
useEffect를 이용하여 compomentdidmount의 사이클 효과를 주어,
렌더링 초기 화면에 바로 더미 데이터를 뿌려 줍니다. 

useEffect(() => {
 axios.get('https://jsonplaceholder.typicode.com/users')
  .then(res => setInfo(res.data))
  .catch(err => console.log(err));
 }, []);

 

가져올 데이터(jsonplaceholder.typicode.com/users): 

 

axios로 데이터 호출 후 첫 화면

 

테이블 게시판 만들기

Board.js(부모 컴포넌트, table)

상위 컴포넌트로서 하위에 Tr, Post, Modal 컴포넌트를 포험하고 있습니다.
모든 데이터를 상위 컴포넌트에서 관리하고, 하위 컴포넌트에 props property 내려줍니다. 

import React, { useEffect, useState, useRef } from "react";
import axios from 'axios';
import Tr from './Tr';
import Post from './Post';
import Modal from './Modal';

const Board = () => {
  const [info, setInfo] = useState([]);
  const [selected, setSelected] = useState('');
  const [modalOn, setModalOn] = useState(false);

  // 고유 값으로 사용 될 id
  // ref 를 사용하여 변수 담기
  const nextId = useRef(11);

//더미 데이터 호출
  useEffect(() => {
    axios.get('https://jsonplaceholder.typicode.com/users')
      .then(res => setInfo(res.data))
      .catch(err => console.log(err));
  }, []);

  const handleSave = (data) => {
    //데이터 수정하기
    if (data.id) { //수정 데이터에는 id가 존재
      setInfo(
        info.map(row => data.id === row.id ? {
          id: data.id,
          name: data.name,
          email: data.email,
          phone: data.phone,
          website: data.website,
        } : row))

    } else { //바로 추가하기
      // 데이터 추가하기 방법1
      // setInfo((prev) => {
      //   return [ ...prev, {
      //     id: nextId.current,
      //     name: data.name,
      //     email: data.email,
      //     phone: data.phone,
      //     website: data.website
      //   }]
      // });

      //데이터 추가하기 방법2
      setInfo(info => info.concat(
        {
          id: nextId.current,
          name: data.name,
          email: data.email,
          phone: data.phone,
          website: data.website
        }
      ))
      nextId.current += 1;
    }
  }

  const handleRemove = (id) => {
    setInfo(info => info.filter(item => item.id !== id));
  }

  const handleEdit = (item) => {
    setModalOn(true);
    const selectedData = {
      id: item.id,
      name: item.name,
      email: item.email,
      phone: item.phone,
      website: item.website
    };
    console.log(selectedData);
    setSelected(selectedData);
  };

  const handleCancel = () => {
    setModalOn(false);
  }

  const handleEditSubmit = (item) => {
    console.log(item);
    handleSave(item);
    setModalOn(false);
  }

  return (
    <div className="container max-w-screen-lg mx-auto">
      <div className='text-xl font-bold mt-5 mb-3 text-center'>고객 정보 리스트</div>
      <table className="min-w-full table-auto text-gray-800">
        <thead className='justify-between'>
          <tr className='bg-gray-800'>
            <th className="text-gray-300 px-4 py-3">Id.</th>
            <th className="text-gray-300 px-4 py-3">Name</th>
            <th className="text-gray-300 px-4 py-3">Email</th>
            <th className="text-gray-300 px-4 py-3">Phone No.</th>
            <th className="text-gray-300 px-4 py-3">Website</th>
            <th className="text-gray-300 px-4 py-3">Edit</th>
            <th className="text-gray-300 px-4 py-3">Delete</th>
          </tr>
        </thead>
        <Tr info={info} handleRemove={handleRemove} handleEdit={handleEdit} />
      </table>
      <Post onSaveData={handleSave} />
      {modalOn && <Modal selectedData={selected} handleCancel={handleCancel} 
      handleEditSubmit={handleEditSubmit} />}
    </div>
  );
};

export default Board;

 

Tr.js(하위1 컴포넌트 <tr>)

 Map 이용하여 user.id 갯수 만큼 Td.js 컴포넌트를 반복해서 불러오고,  props user data property 넘겨줍니다.

import React from 'react';
import Td from './Td';

const Tr = ({info, handleRemove, handleEdit}) => {
    return (
        <tbody>
            {
                info.map(item => {
                    return (
                        <Td key={item.id} item={item} handleRemove={handleRemove} 
						handleEdit={handleEdit} />
                    )
                })
            }
        </tbody>
    );
};

export default Tr;

 

Td.js(하위2 컴포넌트 <td>)

<td> 요소에 User data를 출력하고, 수정과 삭제 버튼을 추가합니다.
아이콘은  font-awesome cdn 설치  아이콘을 이용합니다. 

import React from 'react';

const Td = ({item, handleRemove, handleEdit}) => {
    const onRemove = () => {
        handleRemove(item.id)
    }

    const onEdit = () => {
        handleEdit(item);
    }

    return (
        <>
        <tr className='"bg-white border-2 border-gray-200'>
            <td className='px-4 py-3'>{item.id}</td>
            <td className='px-4 py-3'>{item.name}</td>
            <td className='px-4 py-3'>{item.email}</td>
            <td className='px-4 py-3'>{item.phone}</td>
            <td className='px-4 py-3'>{item.website}</td>     
            <td onClick={onEdit} className='text-center text-purple-400 cursor-pointer show-modal'>
            	<i class="far fa-edit"></i></td>
            <td onClick={onRemove} className='text-center text-purple-400 cursor-pointer'>
            	<i class="far fa-trash-alt"></i></td>
        </tr>
        </>
    )
};

export default Td;

 

데이터 삭제 기능

삭제 버튼에  onClick 이벤트로  onRemove 함수를 연결합니다. 함수 이름은 아무거나 상관없습니다.

<Td.js>

해당 user의 id를 상위의 handleRemove 함수에 전달합니다.

const onRemove = () => {
  handleRemove(item.id)
}

 

<Board.js>

상위에 handleRemove 함수에서 해당 user의 id를 받아와 Array.filter기능을 이용하여,
user table에서 요소의  id가 전달 받은 id가 아닐 경우, true로 리스트에 남고,
같은 id일 경우, false가 되어, 리스트에서 제거가 됩니다.

const handleRemove = (id) => {
  setInfo(info => info.filter(item => item.id !== id));
}

 

추가, 수정, 저장 기능은 아래 포스트로 이동해주세요.

https://goddino.tistory.com/155

 

[js] react 테이블 게시판 만들기 ver.2 (글수정, 저장, 삭제, hooks, form)

Post.js (하위1 컴포넌트, 고객 정보 추가하기 form) import React, { useState } from 'react'; const Post = ({ onSaveData }) => { const [form, setForm] = useState({ name: '', email: '', phone: '', webs..

goddino.tistory.com

반응형

댓글