사용자 입력 값 검사
:
📌 사용자가 입력한 4개의 값이 유효한지 확인한다.유효성 검사 후 값 전달
:
📌 값이 유효하다면, 이 4개의 값을 서버로 전송한다.서버 작업
:
📌 서버는 전달받은 4개의 값을 받아온다.
📌 MySQL 데이터베이스에 4개의 값을 추가한다.서버 응답 처리
:
📌 서버가 추가에 성공하면, 리액트 앱에 응답을 보낸다.리액트에서 응답 처리
:
📌 리액트 앱은 서버로부터의 응답을 받아, 추가가 성공했다면 화면을 다시 렌더링한다.
state 변수를 만들어야한다.
const [company, setCompany] = useState(''); const [position, setPosition] = useState(''); const [startDate, setStartDate] = useState(''); const [endDate, setEndDate] = useState('');
careerViewTable.js
import DashboardLayout from "../../components/common/layout";
import { useState } from "react";
const CareerPage = () => {
//🌟 state 변수 네개, 사용자가 input 태그에 입력한 값을 기억 용도
const [company, setCompany] = useState('');
const [position, setPosition] = useState('');
const [startDate, setStartDate] = useState('');
const [endDate, setEndDate] = useState('');
const onAddCareer = async () => {
// console.log(company, position, startDate, endDate);
if(company === ''){
alert('회사명을 입력해주세요');
return; //company가 비어있으면 (return으로 바로 종료시키고 alert창이 뜬다)
}
if(position === ''){
alert('직책을 입력해주세요');
return;
}
if(startDate === ''){
alert('시작일을 입력해주세요');
return;
}
if(endDate === ''){
alert('종료일을 입력해주세요');
return;
}
}
return (
<DashboardLayout>
<tbody>
<tr>
<td><input onChange={e => setCompany(e.target.value)} /></td>
//변경될때마다 값이 setCompany안에 저장된다.
<td><input onChange={e => setPosition(e.target.value)}/></td>
<td><input onChange={e => setStartDate(e.target.value)} type="date" /></td>
<td><input onChange={e => setEndDate(e.target.value)} type="date" /></td>
</tr>
</tbody>
<tfoot>
<tr>
<td colSpan={4}>
<button onClick={onAddCareer}>추가하기</button>
//추가버튼을 클릭하면 onAddCareer function이 실행됨
</td>
</tr>
</tfoot>
</DashboardLayout>
)
}
export default CareerPage;
나쁜예제
//시작일이 오늘 날짜보다 늦으면 안됨
const today = new Date('');
if (startDate > today){
//컴퓨터 입장에서 startDate가 뭔데???함 (type이 다르기때문에)
alert('시작일은 오늘 날짜보다 늦을 수 없습니다.');
return;
}
좋은예제
//시작일이 오늘 날짜보다 늦으면 안됨
const today = new Date('');
const targetStartDate = new Date(startDate);
if (targetStartDate > today) {
//🌟 이렇게 날짜랑 날짜를 비교해야함
alert('시작일은 오늘 날짜보다 늦을 수 없습니다.');
return;
}
careerViewTable.js
const onAddCareer = async () => {
//시작일이 오늘 날짜보다 늦으면 안됨
const today = new Date('');
const targetStartDate = new Date(startDate);
if (targetStartDate > today) {
alert('시작일은 오늘 날짜보다 늦을 수 없습니다.');
return;
}
//종료일은 비어있어도 됨
if (endDate === '') { //🌟 invalid date, 오류 발생을 방지하기 위해서, "종료일이 비어있으면", 이라는 코드도 작성 중요!
const targetEndDate = new Date(endDate);
if (targetEndDate < targetStartDate) {
alert('종료일은 시작일보다 빠를 수 없습니다.');
return;
}
if (targetEndDate > today) {
alert('종료일은 오늘 날짜보다 늦을 수 없습니다.');
return;
}
}
}
app.js
//career 추가
app.post('/api/career', async (req, res) => {
const { company, position, startDate, endDate } = req.body;
let sql = `
insert into tbl_careers
(email, company, position, start_date, end_date)
values
(
'abc@naver.comddd',
?,
?,
str_to_date(?, '%Y-%m-%d'),
${endDate === '' ? null : `str_to_date(?, '%Y-%m-%d')`}
);
`;
let values = [company, position, startDate];
if (endDate !== '') {
values.push(endDate);
//endDate가 비어있는 문자열이 아닐떄만, values 에 추가해줘 endDate를
}
try { //성공했을때
let [results] = await pool.query(sql, values);
console.log(results);
let [rows] = await pool.query('select * from tbl_careers WHERE id=?', [results.insertId])
console.log(rows);
res.json('커리어 추가 완료!');
} catch (err) { //실패했을때
console.log(err);
res.status(500).json('서버에서 오류 발생함');
}
});
careerViewTable.js
import axios from "axios";
const onAddCareer = async () => {
// 정상적으로 실행되는 코드
try {
let res = await axios.post('/api/career', {
company, position, startDate, endDate
});
//res.data에는 방금 추가한 "객체"가 들어있음
//4개의 데이터를 담아서 줘야함
//성공했을때 뭔가 할것
alert('추가 완료!');
} catch (err) {
console.log(err);
}
careerViewTable.js
import { useState } from "react";
import axios from "axios";
const CareerViewTable = () => {
const [careerList, setCareerList] = useState([]);
//요소가 몇개냐느에 따라 10개 100개 ...된다
const onAddCareer = async () => {
// 정상적으로 실행되는 코드
try {
let res = await axios.post('/api/career', {
company, position, startDate, endDate
});
//res.data에는 방금 추가한 "객체"가 들어있음
//4개의 데이터를 담아서 줘야함
//성공했을때 뭔가 할것
alert('추가 완료!');
// window.location.reload(); //새로고침
//새로고침 대신 생각해 볼수있는것
//방금 추가한 객체를 이미 20개의 객체가 요소로 들어있는
//배열의 마지막 요소로 추가
setCareerList([...careerList, res.data]);
} catch (err) {
console.log(err);
}
}
careerList
가state변수
,
careerList
가 변경되면<CareerViewTable/>
이 다시 그려지면서 아래표가 보여짐.
최초로 렌더링 되면 데이터베이스에 작성되어있는 행들을 받아와서careerList
를 그려주기 때문에 화면상에는 커리어 목록들이 보이게 된다.(직접 새로고침을눌러야함)
- 새로운 커리어 추가하여 데이터베이스에 행추가.
행 추가가 된다고해서 화면에 커리어 목록이 추가되지는 않는다.
새로고침실행
새로고침 실행하면,<CareerViewTable/>
이 다시 최초로 렌더링을 하기 때문에,
데이터베이스에서 행들을 가져오게 되고, 새로고침이전에 데이터베이스에 추가한 행도 보이게 된다.
📌 단점? 깜빡깜빡 현상이 있고, 데이터가 느리다면, 처음 보일때 빈화면이 보일수있다. 사용자 입장에서는 기다렸다가 데이터를 받는다.
careerList
에 직접추가 (state변수)📝 careerList
에 직접추가하는 방법.
- 새로운 커리어 추가하여 데이터베이스에 행추가.
👉 행 추가가 된다고해서 화면에 커리어 목록이 추가되지는 않는다.
-->이거는 첫번째 방법과 같음careerList
에 직접추가.
careerList
가 변화했기 떄문에<CareerViewTable/>
이 다시 그려지고, 우리눈에 보임
app.js
try {
let [rows] = await pool.query('select * from tbl_careers WHERE id=?', [results.insertId])
//console.log(rows);
res.json('커리어 추가 완료!');
} catch (err) {
console.log(err);
res.status(500).json('서버에서 오류 발생함');
}
🌟 console.log(rows) 값은? 배열👇
🌟 console.log(rows[0]) 값? 👇
👉 방금 추가한객체
나옴
배열을 풀겠다
. 배열 안에서 순회가능한 것을 펼치면 아이템 하나하나가 배열로 전달된다.
//ex)
const arr1 = [1, 2, 3];
const arr2 = [4, 5, 6];
const arr3 = [7, 8, 9];
const arrAll = [...arr1, ...arr2, ...arr3];
console.log(arrAll);
// [1, 2, 3, 4, 5, 6, 7, 8, 9]
//arr1, arr2, arr3 모두가 들어감
careerViewTable.js
import { useState } from "react";
import axios from "axios";
const CareerViewTable = () => {
const [careerList, setCareerList] = useState([]);
//요소가 몇개냐느에 따라 10개, 20개, 100개 ...된다
const onAddCareer = async () => {
// 정상적으로 실행되는 코드
try {
let res = await axios.post('/api/career', {
company, position, startDate, endDate
});
//res.data에는 방금 추가한 "객체"가 들어있음
//4개의 데이터를 담아서 줘야함
//성공했을때 뭔가 할것
alert('추가 완료!');
// window.location.reload(); //새로고침
//새로고침 대신 생각해 볼수있는것
//🌟 방금 추가한 객체를 이미 20개의 객체가 요소로 들어있는
//기존의 careerList에 있는요소들과, data, 배열의 마지막 요소로 추가
setCareerList([...careerList, res.data]);
} catch (err) {
console.log(err);
}
}
📝 전개 연산자를 사용하여 기존에 있던 careerList에 있는요소들과, 새로 추가한 res.data를 setCareerList변수
에 넣어준다. (state변수가 변경이 있으면 새로고침을한다.)
onDeleteCareer 함수
는 id라는 매개변수를 받아와 해당 id를 사용하여 Express 서버로 삭제 요청을 보내는 역할.
👉 1. id를 인자로 받는다.
👉 2. 이때, id를 요청의body 데이터
로 담아 서버로 보낸다.
👉 3.서버에서는 해당 id를 기반으로 경력 정보를 삭제하고, 클라이언트에게 응답한다.
👉 4.삭제 요청이 성공하면 res에는 서버에서 온 응답 데이터가 담긴다. 이때, 클라이언트에게 '삭제 완료!' 알림을 띄운다.
careerViewTable.js
import axios from "axios";
const CareerViewTable = () => {
//td셀 클릭시 삭제하는 함수
const onDeleteCareer = async (id) => {
//id를 가지고 express한테 삭제 요청
// id(4)에는 몇번 객체가 삭제되는지에 대한 정보가 들어있음
try {
let res = await axios.delete('/api/career/', { data: {id} }); //감싸서 body에다가 담아줌
alert('삭제 완료!');
//careerList에서 삭제된 id를 가진 요소를 삭제하고 변경
//re-rendering 되면서 마치 우리눈에는 사라진것 처럼 보임
} catch (err) {
alert('삭제 실패!');
}
}
return (
<td
onClick={() => onDeleteCareer(e.id)}
style={{
display: 'flex',
justifyContent: 'center',
alignItems: 'center',
cursor: 'pointer'
}}>
<DeleteSweepIcon />
</td>
)
}
export default CareerViewTable;
app.js
//career 삭제
app.delete('/api/career', async (req, res) => {
const { id } = req.body; //react에서 받아온 body
//삭제할 행 id 는 id에 들어있음
let sql = `DELETE FROM tbl_careers WHERE id=?`;
try {
await pool.query(sql, [id]);
//console.log(results);
res.json('삭제 완료!'); // 삭제를 성공하면,
} catch (err) {
// console.log(err);
res.status(500).json('서버에서 오류 발생함');
}
});
매개변수에 해당하는 값으로,
id에 해당하는 행
을 삭제한다다.
클라이언트로부터 받은 id 값을 사용하여 데이터베이스에서 특정 경력 정보를 삭제하고, 그 결과를 👉 클라이언트에게 응답으로 보내는 역할을 한다.
📌 URL 파라미터 (req.params 사용)
: 요청을 보낼 때 URL에 데이터를 포함시켜서 보낼 수 있다. 예를 들어, /api/career/:id와 같이 URL에 id를 포함시켜 요청할 수 있다. 서버에서는 req.params.id를 사용하여 이 데이터에 접근할 수 있다. 하지만 DELETE 요청에서는 이 방법을 사용하기 어렵다.
📌 요청 본문 (req.body 사용)
: 보통 DELETE 요청에서는 데이터를 요청 본문에 넣어서 보낸다. 이 방법은 HTTP DELETE 요청에서 데이터를 보내는 표준적인 방법이다. 클라이언트에서 요청을 보낼 때, 데이터를 요청 본문에 넣어 서버에게 보내고, 서버에서는 req.body로 이 데이터에 접근할 수 있다.
📝 따라서, HTTP DELETE 요청은 URL에 데이터를 넣기 어렵기 때문에, body에 데이터를 담아서 서버로 보내는 것이 표준적인 방법. 이렇게 하면 서버에서 req.body로 데이터에 접근할 수 있다
filter()
함수는 배열 내 요소를 필터링하는 데 사용됨. 이 함수는 주어진 조건을 만족하는(true가되는) 요소들로 이루어진 새로운 배열을 생성한다.
careerViewTable.js
//td셀
const onDeleteCareer = async (id) => {
//id를 가지고 express한테 삭제 요청
try {
let res = await axios.delete('/api/career/', { data: { id } });
alert('삭제 완료!');
//삭제한 id를 제외한 나머지 요소들만 뽑아서 새로운 배열을 만들어서
//careerList state 변수에 넣어준다.
let newCareerList = careerList.filter((e) => e.id !== id);
setCareerList(newCareerList);
//careerList에서 삭제된 id를 가진 요소를 삭제하고 변경
//re-rendering 되면서 마치 우리눈에는 사라진것 처럼 보임
} catch (err) {
alert('삭제 실패!');
}
}
to be continued...🌟