본문 바로가기
ICIA 수업일지

2021.09.15 수업일지(React.js)

by 주성씨 2021. 9. 15.

- 카테고리 뉴스 검색

 뉴스 카테고리는 비즈니스(business), 연예(Entertainment), 건강(health), 과학(Science), 스포츠(Sports), 기술(technology) 총 여 섯 개이며 화면에 보여 줄 때는 영어로 된 값을 그대로 보여 주지 않고 아래 그림처럼 한글로 보여 준 뒤 클릭했을 때는 영어 값을 사용한다.

- C:\data\react\ex05\src\component\(new)Categories.js

import React from 'react';
import './Categories.css'

const categories=[
    {name : 'all', text:'전체보기'},
    {name : 'business', text:'비즈니스'},
    {name : 'entertainment', text:'엔터테인먼트'},
    {name : 'health', text:'건강'},
    {name : 'science', text:'과학'},
    {name : 'sports', text:'스포츠'},
    {name : 'technology', text:'기술'}
];

const Categories = ({category, onSelect}) => {
    return (
        <div className="categoriesBlock">
            {categories.map(c=>(
                <div className="category" onClick={()=>onSelect(c.name)}>
                    <span className={category===c.name ? 'active':''}>{c.text}</span>
                </div>
            ))}
        </div>
    );
};

export default Categories;

 

- C:\data\react\ex05\src\component\(new)Categories.css

.categoriesBlock {
    display: flex;
    width: 768px;
    margin: 0px auto;
    padding: 1rem;

    @media screen and (max-width: 768px) {
        width: 100%;
        overflow: auto;
    }
}

.category {
    font-size: 1.125rem;
    cursor: pointer;
    text-decoration: none;
    color: inherit;
    padding-bottom: 0.25rem;
    margin-left: 1rem;
}

.category:hover {
    color: #b0b5bb;
}

.category .active {
    color: #22b8cf;
    border-bottom: 2px solid #22b8cf;
    font-weight: 600;
}

.category .active:hover {
    color: #abdfe6;
}

 

- C:\data\react\ex05\src\App.js

import './App.css';
import axios from 'axios';
import {useCallback, useState} from "react"
import NewsList from './component/NewsList';
import Categories from './component/Categories';

const App = () => {
  const [data,setData] = useState(null);
  const onClick = async() => {
    const res = await axios.get('https://newsapi.org/v2/top-headlines?country=kr&apiKey=0d2cfc3452514a4f93903b35e762e40d')
    setData(res.data);
  }

  const [category, setCategory] = useState('all');
  const onSelect = useCallback(category => setCategory(category),[]);
  return (
    <div className="App">
      <Categories category={category} onSelect={onSelect}/>
      <NewsList category={category}/>
    </div>
  );
}

export default App;

 

확인

 

 

- 이제 각 카테고리 클릭 시 각 카테고리에 맞는 뉴스가 나오도록 하겠다.

- C:\data\react\ex05\src\component\NewsList.js

import axios from 'axios';
import React, { useEffect, useState } from 'react';
import NewsItem from './NewsItem';
import './NewsList.css'

const NewsList = ({category}) => {
    const [articles, setArticles] = useState(null);
    const [loading,setLoading] = useState(false);

    const callAPI = async() => {
        setLoading(true);
        try {
            const url = "https://newsapi.org/v2/top-headlines?country=kr";
            const query = category === 'all' ? '':'&category='+category;
            const apiKey = '&apiKey=0d2cfc3452514a4f93903b35e762e40d';
            const res = await axios.get(url+query+apiKey);
            console.log(query);
            setArticles(res.data.articles);
        } catch (e) {
            console.log(e);
            setLoading(false);
        }
        setLoading(false);
    }

    useEffect(()=>{
        callAPI();
    },[category]);

    if(loading){
        return <div className="newsListBlock">불러오는중...</div>
    }

    if(!articles){
        return null;
    }

    return (
        <div className="newsListBlock">
            {articles ? articles.map(acticle => <NewsItem key={acticle.url} article={acticle}/>) : ''}
        </div>
    );
};

export default NewsList;

 

확인

 

 

- 카카오 검색 API를 이용해보도록 하겠다.

https://developers.kakao.com/docs/latest/ko/daum-search/dev-guide#search-book

 

Kakao Developers

카카오 API를 활용하여 다양한 어플리케이션을 개발해보세요. 카카오 로그인, 메시지 보내기, 친구 API, 인공지능 API 등을 제공합니다.

developers.kakao.com

 

- C:\data\react\ex05\src\component\(new)Books.js

import React, { useEffect, useState } from 'react';
import axios from 'axios';
const Books = () => {
    //      변수, 변수세팅함수
    const [books,setBooks] = useState([]);
    const [loading, setLoading] = useState(false);

    const callAPI = async() => {
        setLoading(true);
        try {
            const url = 'https://dapi.kakao.com/v3/search/book?target=title&query=리액트';
            const config = {
                headers:{"Authorization": "KakaoAK 31347cda85f0d6ed06e3025a531f2aca"}
            }
            // axios 라이브러리를 이용해 url, config을 통해 비동기 데이터를 가지고 오도록 한다.
            const res = await axios.get(url,config);
            setBooks(res.data.documents);
            setLoading(false);
        } catch (error) {
            console.log(error);
            setLoading(false);
        }
    }

    useEffect(()=>{
        callAPI();
    },[]);

    if(loading) return <div>Loading...</div>

    return (
        <div>
                                            {/* object를 json 형태로 변환해준다.  */}
            <textarea rows={20} value={JSON.stringify(books,null,2)} readOnly />
        </div>
    );
};

export default Books;

 

- C:\data\react\ex05\src\App.js

import './App.css';

import Books from './component/Books';

const App = () => {
  
  return (
    <div className="App">
      <Books/>
    </div>
  );
}

export default App;

 

- JSON.stringify( )란 무엇인가?

https://steemit.com/kr-dev/@cheonmr/json-stringify

 

JSON.stringify( )란 무엇인가? — Steemit

JSON.stringify( )는 자바스크립트의 값을 JSON 문자열로 변환한다. JSON이란? JSON은 JavaScript Object Notation의 약자로, 브라우저와 서버사이에서 오고가는 데이터의 형식이다. JSON.stringify(value, replacer, space)

steemit.com

 

확인

 

- 이제 데이터를 출력해보도록 하겠다.

- C:\data\react\ex05\src\component\(new)BookItem.js

import React from 'react';

const BookItem = ({book}) => {
    const {title, thumbnail} = book;
    return (
        <div>
            <div>
                <img src={thumbnail} alt="thumbnail"/>
                <div>{title}</div>
            </div>
        </div>
    );
};

export default BookItem;

 

- C:\data\react\ex05\src\component\Books.js

    return (
        <div className="books">
            {books.map(book=><BookItem key={book.isbn} book={book}/>)}
        </div>
    );

 

확인

 

- C:\data\react\ex05\src\component\BookItem.js

import React from 'react';

const BookItem = ({book}) => {
    const {title, thumbnail, authors, price, contents} = book;
    return (
        <div>
            <div className="book">
                <img src={thumbnail} alt="thumbnail"/>
                <div className="data">
                    <div>{title}</div>
                    <div>{authors.map(author=><span>{author}</span>)}</div>
                    <div>{price}</div>
                </div>
                <div className="data">{contents}</div>
            </div>
        </div>
    );
};

export default BookItem;

 

확인

 

- CSS를 줘보자.

- C:\data\react\ex05\src\App.css

.App{
    width: 800px;
    margin: 0px auto;
}
.books {
    border: 1px solid gray;
    padding: 10px;
}
.book{
    border: 1px solid gray;
    padding: 10px;
    margin-bottom: 10px;
    overflow: hidden;
}
.book img{
    width:200px;
    float: left;
    padding: 10px;
    box-shadow: 5px 5px 5px gray;
}
.data:nth-child(2){
    width: 500px;
    float: left;
    margin: 10px;
}
.data div:nth-child(1){
    font-size: 30px;
    margin-bottom: 30px;
    font-weight: bold;
}
.data div:nth-child(2){
    font-size: 20px;
    font-weight: bold;
}
.data div:nth-child(2):before{
    content: "- 저자 :";
}
.data div:nth-child(3){
    font-size: 20px;
    color: red;
}
.data div:nth-child(3):before{
    content: "- 가격 :";
}
.data div:nth-child(3)::after{
    content: "원";
}
.data:nth-child(3){
    color: rgb(26, 26, 26);
    padding: 10px;
    float: left;
    margin: 10px;
}
.data:nth-child(3):before{
    content:"- 책소개 : ";
    font-weight: bold;
}

 

확인

 

 

- 검색어를 통해서 책 검색 결과를 출력해보자.

- C:\data\react\ex05\src\component\Books.js

...
const Books = () => {
...
    const [query, setQuery] = useState('안드로이드');

    const callAPI = async() => {
        setLoading(true);
        try {
            const url = `https://dapi.kakao.com/v3/search/book?target=title&query=${query}`;
...
        } catch (error) {
            console.log(error);
            setLoading(false);
        }
    }

...

    if(loading) return <div>Loading...</div>

    const onKeyPress = (e) =>{
        if(e.key==='Enter'){
            callAPI();
        }
    }

    return (
            <div className="books">
                <div className="condition">
                    <input placeholder="검색어입력" value={query} 
                    onChange={(e)=>setQuery(e.target.value)}
                    onKeyPress={onKeyPress}/>
                </div>
                {books.map(book=><BookItem key={book.isbn} book={book}/>)}
            </div>
    );
};

export default Books;

 

확인

 

 

- 더보기 버튼을 만들어보도록 하겠다.

- 포커스
- 신규 검색 시 page=1
- 더보기 버튼 클릭 시 추가

- C:\data\react\ex05\src\component\Books.js

import React, { useEffect, useRef, useState } from 'react';
import axios from 'axios';
import BookItem from './BookItem';
const Books = () => {
    //      변수, 변수세팅함수
    const [books,setBooks] = useState([]);
    const [loading, setLoading] = useState(false);

    const [query, setQuery] = useState('안드로이드');
    const [page, setPage] = useState(1);
    const txtQuery = useRef();

    const callAPI = async() => {
        setLoading(true);
        try {
            const url = `https://dapi.kakao.com/v3/search/book?target=title&query=${query}&page=${page}&size=3`;
            const config = {
                headers:{"Authorization": "KakaoAK 31347cda85f0d6ed06e3025a531f2aca"}
            }
            // axios 라이브러리를 이용해 url, config을 통해 비동기 데이터를 가지고 오도록 한다.
            const res = await axios.get(url,config);
            if(page===1){
                setBooks(res.data.documents)
            }else{
                setBooks(books.concat(res.data.documents));
            }
            setLoading(false);
        } catch (error) {
            console.log(error);
            setLoading(false);
        }
        txtQuery.current.focus();
    }

    useEffect(()=>{
        callAPI();
    },[page]);
    
    if(loading) return <div>Loading...</div>
    
    const onKeyPress = (e) =>{
        if(e.key==='Enter'){
            setPage(1)
            callAPI();
        }
    }
    
    const onMore = () => {
        setPage(page+1);
    }

    return (
            <div className="books">
                <div className="condition">
                    <input placeholder="검색어입력" value={query} 
                    onChange={(e)=>setQuery(e.target.value)}
                    onKeyPress={onKeyPress} ref={txtQuery}/>
                </div>
                {books.map(book=><BookItem key={book.isbn} book={book}/>)}
                <div className="more" onClick={onMore}>
                    더보기
                </div>
            </div>
    );
};

export default Books;

 

 

확인

 

 

- 리엑트 라우터를 이용해보겠다.

// 서버 종료
ctrl + `

// 새로운 프로젝트 생성
C:\data\react\>yarn create react-app ex05

// Router 라이브러리 설치
C:\data\react\ex05>yarn add react-router-dom

// 프로젝트 스타트
yarn start

 

- C:\data\react\ex05\src\App.js

import './App.css';
import { NavLink, Route, Switch } from 'react-router-dom'
import Books from './component/Books';

const style={
  color:'rgb(0, 153, 153)',
  borderBottom:'5px solid green'
};

const App = () => {


  return (
    <div className="App">
      <div className="menu">
        <span><NavLink activeStyle={style} to="/" exact={true}>도서검색</NavLink></span>
        <span><NavLink activeStyle={style} to="/web">웹문서검색</NavLink></span>
        <span><NavLink activeStyle={style} to="/blog">블로그검색</NavLink></span>
        <span><NavLink activeStyle={style} to="/cafe">카페검색</NavLink></span>
        <span><NavLink activeStyle={style} to="/image">이미지검색</NavLink></span>
      </div>
      <Switch>
        <Route path="/" component={Books} exact={true}/>
        <Route path="/web" component={Books}/>
        <Route path="/blog" component={Books}/>
        <Route path="/cafe" component={Books}/>
        <Route path="/image" component={Books}/>
        <Route render=
          {({location})=>(
          <div>{location.pathname} 페이지가 존재하지 않습니다.</div>
          )}/>
      </Switch>
    </div>
  );
}

export default App;

 

- C:\data\react\ex05\src\component\(new)Web.js

import axios from 'axios';
import React, { useEffect, useRef, useState } from 'react';
import WebItem from './WebItem';

const Web = () => {
    //      변수, 변수세팅함수
    const [webs,setWebs] = useState([]);
    const [loading, setLoading] = useState(false);

    const [query, setQuery] = useState('과학');
    const [page, setPage] = useState(1);
    const txtQuery = useRef();

    const callAPI = async() => {
        setLoading(true);
        try {
            const url = `https://dapi.kakao.com/v2/search/web?target=title&query=${query}&page=${page}&size=3`;
            const config = {
                headers:{"Authorization": "KakaoAK 31347cda85f0d6ed06e3025a531f2aca"}
            }
            // axios 라이브러리를 이용해 url, config을 통해 비동기 데이터를 가지고 오도록 한다.
            const res = await axios.get(url,config);
            if(page===1){
                setWebs(res.data.documents)
            }else{
                setWebs(webs.concat(res.data.documents));
            }
            setLoading(false);
        } catch (error) {
            console.log(error);
            setLoading(false);
        }
        txtQuery.current.focus();
    }

    useEffect(()=>{
        callAPI();
    },[page]);
    
    if(loading) return <div>Loading...</div>
    
    const onKeyPress = (e) =>{
        if(e.key==='Enter'){
            setPage(1)
            callAPI();
        }
    }
    
    const onMore = () => {
        setPage(page+1);
    }

    return (
            <div className="webs">
                <div className="condition">
                    <input placeholder="검색어입력" value={query} 
                    onChange={(e)=>setQuery(e.target.value)}
                    onKeyPress={onKeyPress} ref={txtQuery}/>
                </div>
                {webs.map(web=><WebItem key={web.datetime} web={web}/>)}
                <div className="more" onClick={onMore}>
                    더보기
                </div>
            </div>
    );
};

export default Web;

 

- C:\data\react\ex05\src\component\(new)WebItem.js

import React from 'react';

const WebItem = ({web}) => {
    const {title, datetime, contents, url} = web;
    return (
        <div className="web">
            <div className="webdata">
                <div dangerouslySetInnerHTML={ {__html: title}  } onclick={`location.href=${url}`}></div>
                <div >{datetime}</div>
            </div>
            <div className="webdata" dangerouslySetInnerHTML={ {__html: contents} }></div>
        </div>
    );
};

export default WebItem;

 

 

↑확인요망

 

 

- 프론트 작업 및 백앤드 작업으로 DB 데이터를 CURD 작업해보도록 하겠다.

 

- 새로운 프로젝트를 생성하자.

- C:\data\react\(new)haksa

- C:\data\react\haksa\(new)client - > 기존에 haksa에 있는 파일들을 전부 client에 넣는다.

- C:\data\react\haksa\(new)package.json

{
    "name": "management",
    "version": "1.0.0",
    "private": true,
    "scripts": {
        "client": "cd client && yarn start",
        "server": "nodemon server.js",
        "dev": "concurrently --kill-others-on-fail \"yarn server\" \"yarn client\""
    }
}

 

// 노드몬 설치
npm install -g nodemon

// 폴더에서 웹서버를 구축하기 위한 express와 서버와 클라이언트를 동시에 실행하기 위한 
// concurrently를 아래와 같이 설치
npm install express concurrently

// mysql 연결 할 수 있는 라이브러리 설치
yarn add mysql

 

- 설치 후 확인

- C:\data\react\haksa\package.json

{
    "name": "management",
    "version": "1.0.0",
    "private": true,
    "scripts": {
        "client": "cd client && yarn start",
        "server": "nodemon server.js",
        "dev": "concurrently --kill-others-on-fail \"yarn server\" \"yarn client\""
    },
    "dependencies": {
        "concurrently": "^6.2.1",
        "express": "^4.17.1"
    }
}

 

- C:\data\react\haksa\(new)server.js

const express = require('express');
const app = express();
const port = process.env.PORT || 5000;
app.use(express.json());
app.listen(port, () => {
    console.log(`server is listening at localhost:${port}`);
});
app.get('/', (req, res) => {
    res.send({
        success: true
    })
});

 

- 서버 및 클라이언트 페이지 구동

yarn dev

 

확인

 

확인

 

- C:\data\react\haksa\server.js

...

// mysql 연결
const mysql = require('mysql');

const con = mysql.createConnection({
    host: "localhost",
    user: "haksa",
    password: "pass",
    port: "3306",
    database: "haksadb"
});

...

// 1. 교수목록 가지고 오기
app.get('/pro/list',(req,res)=>{
    var sql = "select * from professors";
    con.query(sql,(err,rows)=>{
        res.send(rows);
    })
})

 

확인

 

- 프론트에 필요한 라이브러리를 깔아보자.

// 라우터 라이브러리 설치
C:\data\react\haksa\client>yarn add react-router-dom

// 자바스크립트 HTTP 클라이언트 설치
C:\data\react\haksa\client>yarn add axios

 

- C:\data\react\haksa\client\package.json

{
....
  },
  "proxy": "http://localhost:5000/" // 추가
}

 

- 리액트에서 할당한 주소로 데이터를 출력해보자.

- C:\data\react\haksa\client\src\(new)component

- C:\data\react\haksa\client\src\component\(new)ProfessorList.js

import React, { useEffect, useState } from 'react';
import axios from 'axios'

const ProfessorList = () => {
    const [list, setList] = useState([]);
    const callAPI = async() => {
        try {
            //                         주소
            const res = await axios.get('/pro/list');
            setList(res.data);
        } catch (error) {
            console.log(error);
        }
    }

    useEffect(()=>{
        callAPI();
    },[]);

    return (
        <div>
            <textarea rows={10} value={JSON.stringify(list, null, 2)}/>
        </div>
    );
};

export default ProfessorList;

 

- C:\data\react\haksa\client\src\App.js

import './App.css';
import ProfessorList from './component/ProfessorList';

function App() {
  return (
    <div className="App">
      <ProfessorList/>
    </div>
  );
}

export default App;

 

확인

 

- C:\data\react\haksa\client\src\component\(new)ProfessorItem.js

import React from 'react';

const ProfessorItem = ({professor}) => {
    const {pcode, pname, dept, hiredate, salary,title} = professor
    return (
        <tr>
            <td>{pcode}</td>
            <td>{pname}</td>
            <td>{dept}</td>
            <td>{hiredate}</td>
            <td>{salary}</td>
            <td>{title}</td>
        </tr>
    );
};

export default ProfessorItem;

 

- C:\data\react\haksa\client\src\component\ProfessorList.js

import React, { useEffect, useState } from 'react';
import axios from 'axios'
import ProfessorItem from './ProfessorItem';

const ProfessorList = () => {
    const [list, setList] = useState([]);
    const callAPI = async() => {
        try {
            //                         주소
            const res = await axios.get('/pro/list');
            setList(res.data);
        } catch (error) {
            console.log(error);
        }
    }

    useEffect(()=>{
        callAPI();
    },[]);

    return (
        <div>
            <table>
                {list ? list.map(item=><ProfessorItem key={item.pcode} professor={item}/>):''}
            </table>
        </div>
    );
};

export default ProfessorList;

 

확인

 

- 이제 format 과 css를 적용해보자.

- C:\data\react\haksa\client\src\App.css

.App {
  width: 800px;
  text-align: center;
  margin: 0px auto;
}

table {
	border-collapse: collapse;
	margin: 0px auto;
	margin-top: 10px;
	margin-bottom: 10px;
}

th {
	background: rgb(242, 242, 242);
	color: black;
  font-size: 30px;
}

th, td {
	border: 1px solid black;
	padding: 10px;
}

.title{
  background-color: rgb(242, 242, 242);
  color: black;
  font-weight: bold;
}

 

- C:\data\react\haksa\server.js

// 1. 교수목록 가지고 오기
app.get('/pro/list',(req,res)=>{
    var sql = 'select *, date_format(hiredate,"%Y-%m-%d") fhiredate, format(salary,0) fsalary from professors order by pcode desc';
    con.query(sql,(err,rows)=>{
        res.send(rows);
    })
})

 

- C:\data\react\haksa\client\src\component\ProfessorList.js

import React, { useEffect, useState } from 'react';
import axios from 'axios'
import ProfessorItem from './ProfessorItem';

const ProfessorList = () => {
    const [list, setList] = useState([]);
    const callAPI = async() => {
        try {
            //                         주소
            const res = await axios.get('/pro/list');
            setList(res.data);
        } catch (error) {
            console.log(error);
        }
    }

    useEffect(()=>{
        callAPI();
    },[]);

    return (
        <div>
            <table>
                <th colSpan={6}>교수목록</th>
                <tr>
                    <td className="title" width="100">교수번호</td>
                    <td className="title" width="100">교수이름</td>
                    <td className="title" width="100">교수직함</td>
                    <td className="title" width="100">담당학과</td>
                    <td className="title" width="200">임용일자</td>
                    <td className="title" width="100">교수급여</td>
                </tr>
                {list ? list.map(item=><ProfessorItem key={item.pcode} professor={item}/>):''}
            </table>
        </div>
    );
};

export default ProfessorList;

 

- C:\data\react\haksa\client\src\component\ProfessorItem.js

import React from 'react';

const ProfessorItem = ({professor}) => {
    const {pcode, pname, dept, hiredate, fhiredate, salary,title, fsalary} = professor
    return (
        <tr>
            <td>{pcode}</td>
            <td>{pname}</td>
            <td>{title}</td>
            <td>{dept}</td>
            <td>{fhiredate}</td>
            <td>{fsalary}</td>
        </tr>
    );
};

export default ProfessorItem;

 

확인

 

- C:\data\react\haksa\client\src\index.js

import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import App from './App';
import reportWebVitals from './reportWebVitals';
import {BrowserRouter} from 'react-router-dom';

ReactDOM.render(
  <BrowserRouter>
    <App />
  </BrowserRouter>,
  document.getElementById('root')
);

// If you want to start measuring performance in your app, pass a function
// to log results (for example: reportWebVitals(console.log))
// or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitals
reportWebVitals();

 

- C:\data\react\haksa\client\src\App.js

import { NavLink, Route } from 'react-router-dom';
import './App.css';
import About from './component/About';
import ProfessorList from './component/ProfessorList';

const style={
  color:'blue'
}

function App() {
  return (
    <div className="App">
      <div className="menu">
        <span><NavLink activeStyle={style} to="/" exact={true}>소개</NavLink></span>
        <span><NavLink activeStyle={style} to="/professors">교수목록</NavLink></span>
        <span><NavLink activeStyle={style} to="/students">학생관리</NavLink></span>
        <span><NavLink activeStyle={style} to="/courses">수강관리</NavLink></span>
      </div>

      <Route path="/" component={About} exact={true}/>
      <Route path="/professors" component={ProfessorList}/>
    </div>
  );
}

export default App;

 

- C:\data\react\haksa\client\src\component\(new)About.js

import React from 'react';

const About = () => {
    return (
        <div>
            <h1>학사관리 시스템 소개</h1>
            <p></p>
        </div>
    );
};

export default About;

 

확인

 

- 학생목록을 출력해보도록 하겠다.

- C:\data\react\haksa\server.js

// 2. 학생목록 가지고 오기
app.get('/stu/list',(req,res)=>{
    var sql = 'select *,date_format(birthday,"%Y-%m-%d") fbirthday from view_stu order by scode';
    con.query(sql,(err,rows)=>{
        res.send(rows);
    })
})

 

- C:\data\react\haksa\client\src\App.js

import { NavLink, Route } from 'react-router-dom';
import './App.css';
import About from './component/About';
import ProfessorList from './component/ProfessorList';
import StudentList from './component/StudentList';

const style={
  color:'blue',
}

function App() {
  return (
    <div className="App">
      <div className="menu">
        <span><NavLink activeStyle={style} to="/" exact={true}>시스템소개</NavLink></span>
        <span><NavLink activeStyle={style} to="/professors">교수관리</NavLink></span>
        <span><NavLink activeStyle={style} to="/students">학생관리</NavLink></span>
        <span><NavLink activeStyle={style} to="/courses">수강관리</NavLink></span>
      </div>
      <Route path="/" component={About} exact={true}/>
      <Route path="/professors" component={ProfessorList}/>
      <Route path="/students" component={StudentList}/>
    </div>
  );
}

export default App;

 

- C:\data\react\haksa\client\src\component\(new)StudentList.js

import axios from 'axios';
import React, { useEffect, useState } from 'react';
import StudentItem from './StudentItem';

const StudentList = () => {
    const [list, setList] = useState([]);
    const callAPI = async() => {
        try {
            //                         주소
            const res = await axios.get('/stu/list');
            setList(res.data);
        } catch (error) {
            console.log(error);
        }
    }

    useEffect(()=>{
        callAPI();
    },[]);

    return (
        <div>
            <table>
                <th colSpan={6}>학생목록</th>
                <tr>
                    <td className="title" width="100">학생번호</td>
                    <td className="title" width="100">학생이름</td>
                    <td className="title" width="100">학과</td>
                    <td className="title" width="50">학년</td>
                    <td className="title" width="200">생년월일</td>
                    <td className="title" width="150">담당교수/학과</td>
                </tr>
                {list ? list.map(item=><StudentItem key={item.pcode} student={item}/>):''}
            </table>
        </div>
    );
};

export default StudentList;

 

- C:\data\react\haksa\client\src\component\(new)StudentItem.js

import React from 'react';

const StudentItem = ({student}) => {
    const {scode, sname, dept, year, fbirthday, birthday,pname, pdept} = student
    return (
        <tr>
            <td>{scode}</td>
            <td>{sname}</td>
            <td>{dept}</td>
            <td>{year}</td>
            <td>{fbirthday}</td>
            <td>{pname}/{pdept}</td>
        </tr>
    );
};

export default StudentItem;

 

확인