본문 바로가기

React 수업 정리

게시판 구현해보기(1)

배운것들을 활용해서 게시판을 만들어 보았다.

 

크게 4개의 컴포넌트로 구상하였는데

 

첫번째는 게시글 목록을 보여줄 List 컴포넌트, 두번째는 목록에서 제목을 누르면 내용을 보여줄 상세페이지

Detail컴포넌트, 세번째는 상세페이지에서 내용을 바꿀 수 있게 해주는 수정페이지 Modify 컴포넌트,

네번째는 게시글 목록에서 글쓰기버튼으로 게시글을 추가하게해주는 Create 컴포넌트이다.

 

일단 다 기본 틀만 만들어놓고  서버에 필요한것들을 다 인스톨 한 뒤

 

server.js 에 이렇게 작성해준다.

const express = require('express');
const bodyParser = require('body-parser');
const mysql = require('mysql');
const cors = require('cors');

//express 사용하기 위한 app 생성
const app = express();

//express 사용할 서버포트 설정
const PORT = 5000;

app.use(cors());
app.use(bodyParser.json());

//DB 접속
const db = mysql.createConnection({
    host : 'localhost',
    user: 'react',
    password: 'mysql',
    port:'3306',
    database:'db_react'
});

// express 접속
app.listen(PORT, ()=>{
    console.log(`server connecting on : http://localhost:${PORT}`);
});

//db 연결
db.connect((err)=>{
    if(!err){
        console.log("seccuss");

    }else{
        console.log("fail");
    }
});


// --------- DB에서 값을 가져오기 -------------

// / => root 연결시 보여지는 기본화면 설정
app.get('/', (req, res) =>{
    res.send('React Server Connect Success!!');
});

 

그리고 화면이 나와야하니 App.js에 

import React from 'react';
import { BrowserRouter, Route, Routes } from 'react-router-dom';
import List from './component/List';
import Detail from './component/Detail';
import Create from './component/Create';
import Modify from './component/Modify';


function App() {
  return (
    <BrowserRouter>
        <Routes>
            <Route path='/' element={<List />} />
            <Route path='/list' element={<List />} />
            <Route path='/detail/:id' element={<Detail/>} />
            <Route path='/create' element={<Create />} />
            <Route path='/modify/:id' element={<Modify/>} />
        </Routes>
    </BrowserRouter>
);
}

export default App;

 

화면이나오도록 , 누르면 페이지가 넘어 갈 수 있도록 코드를 짜준다.

 


 

게시글 목록 페이지 List 구현하기

 

일단 게시글 목록페이지에서 구현할 기능은 검색기능, 페이지네이션, 최신/조회순 정렬 크게 3가지이다.

 

 return (
            <div className='list'>
                <Link  style={{ textDecoration: "none"}} to={'/list'}><h2>자유게시판</h2></Link>
                <hr />
                
                       <table>
                <thead>
                    <tr>
                        <th>번호</th>
                        <th>제목</th>
                        <th>작성자</th>
                        <th>작성일</th>
                        <th>조회</th>
                    </tr>
                </thead>
                <tbody>
                  {
                     currentItems.map(b => (
                        

                    <tr key={b.id} >
                    <td>{b.id}</td>
                    <td><Link to={`/detail/${b.id}`} onClick={() => plusViewCount(b.id)}>{b.title}</Link></td>
                    <td>{b.writer}</td>
                    <td>{b.reg_date.substring(0,10)}</td>   
                    <td>{b.viewCount}</td>
                    </tr>

                        ))
                    }
                </tbody>
                </table>
                
         )

 

일단 화면에 표시할 항목들을 적어주고

  const [ list, setList ] = useState([]);
  
  const getListData = async () => {
        const lists = await axios.get('/list');
        setList(lists.data);
    }
    
     useEffect(() => {
        getListData();
    },[]);

 

app.get('/list', (req, res) => {
    console.log('/list');
    const sql = 'select * from free_board order by id desc';
    db.query(sql, (err, data) => {
        if(!err){
            res.send(data);
        } else {
            console.log(err);
            res.send('전송오류');
        }
    })
});

 

를 통해 데이터를 가져올 수 있게한다.

가져올 수 있게하기 위해 DB는 미리 만들어두었다

 

db의 구성은 이러하다. 

create table free_board (
id bigint auto_increment primary key,
title varchar(30),
contents varchar(500),
writer varchar(20),
reg_date timestamp DEFAULT now(),

viewCount int default 0
);

 

리스트를 만들면서 Create 전에 데이터를 확인할 수 있게 데이터를 몇개 넣어두자.

 

이제

app.post('/list/:id', async (req, res) => {
    const { id } = req.params;

    const sql = `update free_board set viewCount = viewCount + 1 where id = ${id}`;

    db.query(sql, (err, data) => {
        if(!err){
            res.sendStatus(200); 
        } else {
            console.log(err);
            res.send('전송오류');
        }
    })
});

 

를 통해 조회수가 상세페이지로 넘어가면서 +1  올라가도록 만들어주고.

 

검색기능을 구현해보도록하자.

 

 const [searchTerm, setSearchTerm] = useState('');

 const [filteredList, setFilteredList] = useState([]);

 const [searchOption, setSearchOption] = useState('title');

 

크게 3개의 상태를 정의하는데 

 

검색입력창의 상태, 검색하고 필터링된 리스트의 상태, 그리고 무엇으로 검색할건지의 대한 옵션의 상태를 정의해준다.

 

 const handleSearch = () => {
        if (searchTerm) {
            const filtered = list.filter(item => {
                if (searchOption === 'title') {
                    return item.title.includes(searchTerm);
                } else if (searchOption === 'writer') {
                    return item.writer.includes(searchTerm);
                } else if (searchOption === 'both') {
                    return item.title.includes(searchTerm) || item.writer.includes(searchTerm);
                }
                return false;
            });
            setFilteredList(filtered);
        } else {
            setFilteredList(list);
        }
        setSearchTerm('');
    };

 

정의 후 옵션의 상태에따라 포함 유무에따라 필터링 할 수 있도록 이렇게 짜준 후, 검색 후에 내용이 비워지도록 설정.

 

  const getListData = async () => {
        const lists = await axios.get('/list');
        setList(lists.data);
        setFilteredList(lists.data);
    }

 

데이터를 가져올 때도 setFilteredList에도 가져오도록 추가설정.

   const handleKeyPress = (event) => {
        if (event.key === 'Enter') {
            handleSearch();
        }
    };

 

엔터를 눌렀을 때도 검색이 가능하도록 추가설정해준다.

 

     <select value={searchOption} onChange={(e) => setSearchOption(e.target.value)}>
                <option value="title">제목</option>
                <option value="writer">작성자</option>
                <option value="both">제목+작성자</option>
                </select>

                <input 
                className='search'
                type="text" 
                placeholder="검색어 입력" 
                value={searchTerm} 
                onChange={(e) => setSearchTerm(e.target.value)} 
                onKeyDown={handleKeyPress}
            />

            <button className='searchBtn' onClick={handleSearch}>검색</button>

 

그리고 화면에 나오도록 이렇게 구현해주면 검색기능이 구현된다.

 

이제 게시글이 너무많으면 페이지가 생성되어 넘어갈 수 있도록 구현해보자.

이번에는 8개가 넘어가면 페이지가 생성되고 넘어가도록 구현해 보도록 하겠다.

 

  const [currentPage, setCurrentPage] = useState(1);
  
  const itemsPerPage = 8;

 

페이지의 상태와  한페이지 당 게시글의 수를 정의주도록 한다.

 

검색기능 구현에 setCurrentPage(1); 를 넣어서 검색 후 1페이지가 되도록 추가해주고.

 

   const totalPages = Math.ceil(filteredList.length / itemsPerPage);
   const startIndex = (currentPage - 1) * itemsPerPage;
   const currentItems = filteredList.slice(startIndex, startIndex + itemsPerPage);

 

전체페이지, 현재페이지, 시작인덱스를 정의해주도록 하자.

 

 const handlePageChange = (pageNumber) => {
        setCurrentPage(pageNumber);
    };


    const onPre = () => {
        if (currentPage > 1) {
            setCurrentPage(currentPage - 1);
        }
    };

    const onNext = () => {
        if (currentPage < totalPages) {
            setCurrentPage(currentPage + 1);
        }
    };

 

그러고 페이지 이동을 구현.

 

   <div className='pagination'>
                    <button onClick={onPre} disabled={currentPage === 1}>
                        이전
                    </button>

                    {Array.from({ length: totalPages }, (_, index) => (
                        <button 
                            key={index + 1} 
                            onClick={() => handlePageChange(index + 1)} 
                            disabled={currentPage === index + 1}
                        >
                            {index + 1}
                        </button>
                    ))}

                    <button onClick={onNext} disabled={currentPage === totalPages}>
                        다음
                    </button>

 

선택한 페이지와 1은 이전, 최대페이지면 다음 버튼을 disabled 해서 비활성화 시켜주면서 화면에 구성하면 

페이지네이션이 구현된다.

 

이제 정렬 기능만 넣으면 리스트 기능은 구현은 끝이난다.

 

    const [sort, setSort] = useState('latest');

 

정렬 상태를 일단 정의해주고

 

  const sortList = (list) => {
        return [...list].sort((a, b) => {
            if (sort === 'latest') {
                return new Date(b.reg_date) - new Date(a.reg_date);
            } else if (sort === 'views') {
                return b.viewCount - a.viewCount;
            }
            return 0;
        });
    };

 

sortList 기존 list를 스프레드로 받아와서 sort의 상태에따라 시간순, 조회순으로 정렬 할 수있도록 기능을 만들어준다.

   useEffect(() => {
        const sortedList = sortList(filteredList);
        setFilteredList(sortedList);
    }, [sort]);

 

sort가 바뀔때마다 필터링 되어서 정렬 할 수있도록 useEffect해준다.

 

     <div className='sort-container'>
                <div className='sort'>
                    <button 
                        className={sort === 'latest' ? 'active' : ''} 
                        onClick={() => setSort('latest')}
                    >
                        최신순
                    </button>
                    <button 
                        className={sort === 'views' ? 'active' : ''} 
                        onClick={() => setSort('views')}
                    >
                        조회순
                    </button>
                </div>
            </div>

 

이제 화면에서 최신순 , 조회순 버튼을 만들어주고 active 되면 버튼에 불이 들어오도록 css할 수 있게 active를 넣어주었다.

 

 


 

 

리스트 페이지 완성

 

페이지에 따라 게시글 목록이 넘어가고 검색기능, 최신/ 조회순으로 정렬 할 수 있는 기능이 구현된 것을 볼 수 있다.

 

'React 수업 정리' 카테고리의 다른 글

게시판 구현해보기(3)  (1) 2024.09.24
게시판 구현해보기(2)  (0) 2024.09.24
Board 만들어보기  (0) 2024.09.19
React 5일차  (0) 2024.09.10
React 4일차.  (3) 2024.09.09