1) create database shopping 2) crate table products( ) 3) insert문으로 데이터 생성
예제 테이블
데이터베이스 생성
create database shopping
use shopping
테이블 생성
create table products( p_id int primary key auto_increment, p_name varchar(20) not null, p_price int not null, p_desc text , p_quantity int not null, p_img varchar(100) )
데이터삽입
insert into products(p_name, p_price, p_desc, p_quantity, p_img) values("기초스킨케어 1",50000, "인기 있는 상품입니다.",80, "images/cosmetic1.JPG"); insert into products(p_name, p_price, p_desc, p_quantity, p_img) values("기초스킨케어 2",70000, "인기 있는 상품입니다.",50, "images/cosmetic2.JPG"); insert into products(p_name, p_price, p_desc, p_quantity, p_img) values("기초스킨케어 3",40000, "인기 있는 상품입니다.",30, "images/cosmetic3.JPG"); insert into products(p_name, p_price, p_desc, p_quantity, p_img) values("기초스킨케어 4",70000, "인기 있는 상품입니다.",60, "images/cosmetic4.JPG");
똑같이 입력해주면 아래와같은 데이터베이스 테이블이 하나 생성된다.
예제 테이블
2.express서버에 mysql설치
npm install mysql
1) mysql 라이브러리 불러오기 //const mysql = require("mysql"); 2) mysql접속 생성
//express 서버 만들기
const express = require("express");//import express
const cors = require("cors");
//mysql import
const mysql = require("mysql");
//서버 생성 --> express( )호출
const app = express();
//프로세서의 주소 포트번호 지정
const port = 8080;
// JSON형식의 데이터를 처리할수 있도록 설정
app.use(express.json());
// 브라우저의 CORS 이슈를 막기 위해 사용하는 코드
app.use(cors());
//sql연결선
const conn = mysql.createConnection({
host:"localhost",
port:"3306",
user:"root",
password:"1234",
database:"shopping"
})
//sql 연결하기
conn.connect()
// get요청시 응답 app.get(경로,콜백함수)
app.get('/products',(req,res)=>{
conn.query('select * from products',function(error,result,field){
if(error){
res.send(error)
}
res.send(result);
console.log(result);
})
});
app.get("/products/:id",(req,res)=>{
const params = req.params;
const {id} = params;
res.send(`id는${id}이다`)
})
//서버구동
app.listen(port,()=>{
console.log("서버가 돌아가고있습니다.")
})
아까 객체로 보내줬던 값을 이번에는 데이터베이스에서 조회해서 페이지로 전달해주고 있다.
배열에 데이터베이스에서 받아온 값들이 객체로 들어가서 전달된다.
sql을 받아서 출력한값
여기까지 기본서버와 express서버를 만들었고 url파라미터를 받는 방법과 mysql을 연결해서 데이터베이스를 받아오는 걸 공부해 봤다. 다음포스팅은 데이터베이스에서 받아온 데이터를 서버에 올려주고 서버에 올린 값을 리액트에서 axios로 받아서 이용하는 페이지를 만들어 보겠다.
나는 프런트엔드 수업을 듣고 있어서 서버를 만드는 방법은 배웠지만 이 서버가 어떤 원리로 동작하고 어떤 코드가 정확하게 어떤 역할을 하는지는 간단한 설명만 듣고 넘어갔다. 아마 백엔드는 이것보다 배울게 많겠지.. 지금은 리액트를 하느라 바쁘지만 나중에 조금 시간이 생긴다면 서버에 대해서 조금 더 공부해보고 싶다.
이렇게 서버에서 값을 받아오는 axios에 대해서 배웠다. 또 함수를 묶어서 커스텀hook을 만들어서 사용할수도 있다는걸 알게되었다 물론 아직 스스로 이런걸 짤수있는 능력은 없지만 읽어서 어떻게 돌아가는지는 아니까 잘 찾아서 따라할수있지않을까? axios는 promise를 기반으로 만들어졌기때문에 async await 말고도 .then으로도 사용할수 있다. 일단 이런건 쓸려면 자바스크립트가 기초가되야되는데 이번에 비동기함수를 보면서 자바스크립트에서 부족한점을 알게된것같다.
여기서는 우선 App컴포넌트 위에 상태값으로 사용할 초기값을 변수로 만들어주고 상태변환함수로 사용할 reducer 도 만들어줬다 reducer는 dispatch에서 보내주는 action 객체를 받아서 상태값을 return 해준다. action 객체 의 type을 스위치문의 조건으로 사용해서 조건에 맞을 때 상태를 넣어준다.
컴포넌트에서 상태값을 만들 때 useState처럼 구조분해할당으로 상태값과 상태변환함수를 받아주고
이렇게 dark라는 상태값을 하나 추가해 주고 버튼을 누르면 상태값이 변경된다. 모드변경모드를 누를 때마다 상관없는 박스 키우기가 콘솔에 뜨게 되는데 이유는 dark상태값이 변경되면서 컴포넌트가 리렌더링 되고 createBox함수도 리렌더링 되면서 같은 모양의 함수이지만 다른 주소를 가지게 되면서 Box컴포넌트에서 useEffect가 다른 함수라고 인식하게 되어 실행되어서 그렇다. 그래서 이를 막기 위해서는 함숫값이 변경되지 않게 해줘야 한다. 사이즈가 변경될때만 함수를 다시호출하고 변경되지않을 때는 저장되어있는 함수를 그대로 이용해서 같은주소의 함수가 보내지게 해줘야한다.
이렇게 써주면 useCallback이 boxstyle을 주던 함수를 저장하게 되고 size가 변경될 때만 함수가 다시 만들어진다.
사이즈가 변경되지 않았을 때는 원래 있던 함수를 box컴포넌트에 보내주고 주소가 이전과 같기 때문에 useEffect에서도 다시 실행되지 않는다.
저번 useMemo와 같이 useCallback도 값을 저장해 뒀다가 쓰는 방식이기 때문에 많이 쓰면 자원을 낭비하게 된다. 꼭 필요할 때 적절히 쓸 수 있도록 해야 한다. 아직은 언제 어떤 방식으로 써야 적절하게 쓰는 건지 감이 잘 오지는 않는다. 나중에 포트폴리오를 하면서 쓰다가 보면 감이 오겠지.
타입이 객체로 바뀐 것뿐인데 숫자를 바꿔도 'useEffect호출'이 콘솔에 뜨는 걸 볼 수 있다.
이건 타입에서 생기는 문제인데 string타입은 변수에 값이 바로 담겨있기 때문에 useEffect에서 봤을 때
같은 값이면 실행시키지 않는다.
그러나 객체타입은 값을 바로 가지는 게 아니고 주소값을 가지기 때문에 상태값이 변경되어 리렌더링이 일어나고 location이 다시 실행되어서 같은 모양의 객체를 만들어도 가지고 있는 주소값이 이전과 다르기 때문에 useEffect에서 보기에는 다른 값이라고 여기게 되어서 리렌더링이 일어날 때마다
이렇게 사이즈로 들어갈 sizes객체를 하나 만들고ButtonTotal에 props로 받아오는 size를 css로 작성해서 sizestyle에 저장해 준다. 그러면 스타일이 변수에 저장되게 되고 변수를 스타일 컴포넌트에 넣어주면 스타일 컴포넌트가 만들어지기 전에 미리 조건으로 스타일을 정해서 컴포넌트에 넣어주게 된다.
코드를 보면 스타일컴포넌트를 만들기 전에 변수에 css를 저장하고 css가 저장된 변수를 스타일 컴포넌트에 넣어서 사용해 준다. ${colorStyle} , ${sizestyle}
꼭 이렇게 코드를 작성하는 게 더 좋다는 건 아니고 이러면 보기에 조금 깔끔해 보이기는 하는데
내 개인적인 생각으로는 스타일 컴포넌트 자체가 모든 스타일을 컴포넌트 안에 정의해 줘서 코드를 간결하게 해 주는데 이렇게 밖에서 만들어서 적용해 주면 저 변수에 어떤 게 들어가는지 또 찾아가서 봐야 하고 좀 '굳이?'라는 생각이 들긴 한다. 취향인 쪽을 쓰거나 취업을 한다면 사수가 원하는 방향으로 써주면 되겠지... 그래도 나는 안에 다 들어있는 게 좋다고 생각함 왔다 갔다 하는 거 진짜 너무 힘들다.. 컴포넌트도 많아서 걔네들 돌아가면서 보는 것도 힘든데..
Polished 라이브러리-- wooah(우아한..)
Polished
저번에 sass와 styled-component를 설치할 때처럼 사용하려는 프로젝트 폴더로 이동해서 설치해 준다
npm install --save polished
이제 polish에 있는 기능을 import 해서 사용해 주면 된다. 여기서는 lighten이라는 기능을 사용해 줄 것이다.
App에서 보내준 상태값과 상태값을 바꾸는 함수들을 Dialog에서 받아서 함수는 버튼에 클릭이벤트로 넣고 dialog는
조건문으로 dialog가 true일 때는 return null 이 되게 조건을 준다. 그러면 dialog에서 null을 return 해주기 때문에 결과적으로 아무것도 보이지 않는다.
삭제버튼을 클릭하면 dialog가 뜨고 확인이나 취소를 클릭하면 dialog가 사라지는 걸 확인할 수 있다.
이 제거의 다 왔다.. dialog가 생기고 없어질 때 지연시간을 주고 생길 때는 아래에서 올라오게 해주고 사라질 때는 아래로 내려가는 애니메이션 효과를 주겠다. 지연시간을 주려면 처음에 생길때는 크게 상관없지만 사라질때는 useEffect를 이용해서 값이 변경될 때 애니메이션을 실행시켜 주고 지연시간뒤에 애니메이션을 지워준뒤에 dialog가 사라지도록 해줘야 한다..
나도 아직 완전히 이해한 게 아니라서 최대한 풀어서 설명해도 이 정도가 나의 최선...
바로 시작!
Dialog.js
styled-components로 애니메이션만들기
styled-components에서 keyframes를 import해준다음 애니메이션을 만들어준다.
styled-componets에 애니메이션적용
컴포넌트 안에 animation이름을 넣어주고 애니메이션실행시간(animation-duration) 애니메이션 끝난 후상태(animation-fill-mode)를 설정해 줬다 지금은 컴포넌트가 생길 때 실행될 애니메이션만 추가되어 있고 사라질 때 실행될 애니메이션도 추가해 주겠다.
Dialog에서 스타일컴포넌트에 disappear라는 props를 보내주고 disappear가 true이면 아래의 css코드가 적용되면서 윗줄에 있는 animation-name을 덮어써준다.
props.disappear
이렇게 disappear props를 전달해 주는데 dialog가 false가 될 때(창이 사라질 때) → disappear는 true가 되면서 slideDown, fadeOut 애니메이션이 실행되게 해 준다.
이렇게 하면 실행될 것 같지만 실행되지 않는다
애니메이션이 실행되기 전에 이미 return null이 돼서 사라져 있기 때문..
그래서 애니메이션을 실행한 후에 사라지도록 조건과 값을 주겠다.
조건을 주기 위해 Dialog컴포넌트 안에 상태값(State)을 2개 만들어줬다 animate , localdialog
animate
dialog가 false가 돼서 사라질 때(사라지는 애니메이션 실행) true가 되고
애니메이션의 끝나는 시간인(animation-duration) 0.5초 뒤에 false가 되게 해 준다.
(사라지는 애니메이션 지속시간 동안만 true가 되는 상태값)
localdialog
지금은 확인이나 취소버튼을 클릭해서 dialog가 false로 바뀌면 바로 return null이 되는데
바로 return null이 되지 않게 해줘야 한다.
localdialog에 dialog값(true)을 넣어준다 dialog가 false로 바뀌고 localdialog가 true일 때는
return null을 하지 않고
animate상태값을 true로 만들어주고 사라지는 애니메이션을 0.5초 실행 후 animate값을 false로 바꿔준다
그 후에 localdialog값(true)도 dialog값(false)과 똑같이 만들어주고