React.createElement(dom스타일, props, 자식요소) 를 매개변수로 하는 React에서 제공하는 함수.
여기서 잠깐 Props(Properties : 속성) 부모 요소가 자식 컴포넌트에게 전달하는 속성(데이터)라고 생각하면 편하다. React는 컴포넌트라는 것을 사용하는데 컴포넌트는 HTML태그 처럼 사용하는 일종의 '함수'이다. 즉 React는 함수 안에 함수가 있는 형태를 띄고 있는데 이러한 특성 때문에 React의 데이터 전달은 단방향으로 흘러가는 형태를 가지고 있다.
App은 React.Component 를 상속받아서 render라는 함수를 호출하며 return 값으로 DOM을 그려준다.
위와 같은 코드는 ES6 문법인데 가독성이 떨어지고 알아보기 어렵다.
그래서 사용하는 것이 JSX 문법이다. 브라우저에서 호환이 되지 않기 ES6 문법에서 ES5로 바꿔주는 과정이 필요하다. 그러기 위해 바벨이 필요하다. 이런 이유로 React에서 Webpack(웹팩)과 Babel(바벨)은 뗄레야 뗄 수 없는 관계다.
<script type="text/babel">
// type="text/babel" 스트립트의 내용을 babel로 트랜스 파일 하겠다. -->
class LoginBtn extends React.Component {
// class 컴포넌트
// 컴포넌트로 생성할 클래스에 상속
constructor(props){
// 부모 생성자 호출
super(props);
// state 키값을 정해진 이름으로 사용해야한다. (state는 컴포넌트의 상태값이며 바뀌면 리렌더링이 된다.)
this.state = {
isLogin: false;
}
}
// jsx 문법에서 html 영역에 {} 중괄호 사용하면 javascript를 이용할 수 있다.
// HTML 문법과 달리 ReactDOM은 onClick (on 뒤에 대문자를 넣어)
// onClick 이벤트에는 {} 안에 실행식을 넣으면 반환값이 할당되는 것이다. (한번 호출됨)
// onClick (클릭이 될 때마다) 호출해야하니 함수의 값이 들어가야한다.
// state는 이전 내용이 보관되어 있고 다시 리렌더링 할 때 이전 값을 가져와서 할당해준다.
render(){
let a = 1;
return (
<div>
<div>
<button onClick={() => {this.setState({isLogin: !this.state.isLogin})}}>{this.state.isLogin ? "LogOut" : "Login"}</button>
</div>
이건 일반 변수 : {a}
<button onClick={() => {a++; console.log(a)}}>증가</button>
</div>
)
}
}
// createRoot 브라우저 DOM 노드 안에 리액트 컴포넌트들을 보여주도록 하기위해서 root를 만들수 있도록 한다
const root = ReactDOM.createDOM(document.querySelector("#root"));
// 리액트 root의 브라우저 DOM 노드 안에 JSX를 보여지도록 하기위해서 root.render 호출
// root 안에서 LoginBtn 컴포넌트를 보여지도록 하고, 이 안에서 DOM을 조작할 것이다.
root.render(
<LoginBtn />
)
</script>
여기서 주의! React는 상태(State)가 변해야 리렌더링을 해준다. 위 코드에서 첫번째 Button에서는 onClick 했을 때 setState함수로 state 값을 변경했기 때문에 클릭하면 Login과 Logout이 번갈아 나오는 것을 확인할 수 있다. 그러나 두번째 button에서 onClick에서는 상태값이 변하지는 않고 a라는 변수의 값만 변하기 때문에 console창에서 1씩 증가하는 것을 볼 수 있지만 리렌더링이 되지 않기 때문에 증가하지 않음을 확인할수 있다.
잠깐 프렘임워크와 라이브러리의 차이를 간단하게 알아보자. 프레임워크는 전체적인 흐름을 스스로가 쥐고 있으며 사용자는 그 안에서 필요한 코드를 짜서 넣으며, 라이브러리는 사용자가 전체적인 흐름을 만들며 라이브러리를 가져다 쓰는 것이라고 할 수 있다. (프레임 워크 : 디렉터리 구성이 있음 / 라이브러리 : 디렉터리 구성 없음)
2. React 탄생배경
SPA(Single Page Application) 앱을 사용하는 것같은 사용감이 있는 웹페이지
SPA(Single Page Application)의 이전 세대에는 자바스크립트의 DOM 제어를 할 때 제이쿼리를 사용했었다. 제이쿼리의 편리성 때문에 막 쓰기 시작하면서 가독성이 떨어지고 최적화가 안되서 프로젝트가 무거워졌다. 초기 시절에는 인기가 많았었다. 그리고 SPA의 등장을 했는데 Google의 Gmail 에서 인기가 좋았다. Backbone, AngularJS를 사용한 SPA 환경을 구축했고 DOM을 다루는 방식은 제이쿼리였다. 이런 배경에 React가 탄생했고 많은 개발자들 사이에서 자연스럽게 생태계가 커지게 됬다. 제이쿼리의 DOM 제어를 사용할 필요가 없어졌고 React의 가상 DOM을 사용해서 제어가 가능해졌다. 웹페이지는 수정하면 처음부터 다시 랜더링을 해야하는데 React는 부분만 랜더링이 가능하다.
3. React의 특징
React는 다음과 같은 특징을 가지고 있다.
데이터의 흐름 / 컴포넌트의 구조 / 가상DOM (Virtual DOM) / props와 state / JSX
1) 데이터의 흐름
부모 -> 자식
Vue, Angular는 양방향 데이터의 바인딩을 가지고 있는 반면에 React는 단방향 데이터의 흐름이다. 단방향의 장점으로는 개발하고 있는 프로젝트가 커져도 데이터의 흘듬을 유추하기가 어렵지 않다.
2) 컴포넌트와 컴포넌트의 구조
컴포넌트는 하나의 객체 하나의 페이지의 구성 요소의 하나의 UI 단위, UI 여러개로 나누어 놓은 것.
3) 가상DOM (Virtual DOM)
DOM은 HTML과 CSS의 내용을 트리구조를 가지고 있고 브라우저는 DOM이 변경되면 화면을 다시 그린다. DOM이 변경되고 난뒤의 동작이 무겁고 비용이 많이 든다. 가상DOM을 이용하면 DOM이 변경이 되도 비용이 최소화 된다. 예를 들면 DOM이 1000번 리렌더링을 해야 하는 경우가 발생할 수 있다. 가상DOM을 이용하면 작업을 모아서 처리를 한번에 해준다.
4) props & state
props
- 데이터 전달이 목적이다.
- 함수의 변수처럼 사용하는 느낌
- 부모 컴포넌트가 자식 컴포넌트에게 전달한 값
- props 전달할 때 "props 드릴링"을 피해서 잘 작성해야한다.
state
- 상태를 관리하기 위한 값
- 관리할 데이터를 유지시키는 것이 목적이다.
- 컴포넌트(UI를 나누어 놓은 단위 객체)의 내부에 값을 선언하고 페이지가 동작하는 동안 유지되고 변경될 데이터
React를 사용할 떄 사용할 새로운 문법 Html 파일과 구문의 가독성을 높이고 내용을 줄여서 사용할 수 있다. Webpack : JSX 문법으로 작성한 파일을 js로 변환하고 번들링도 하기위한 속성을 관리한다. !! 다음에는 Webpack과 Babel에 대해서 포스팅 할 예정이다.
const deleteSql = "DELETE FROM products WHERE id =?;";
mysqlConnect.query(deleteSql, [1], (err) => {
if(err)
console.log("삭제할 데이터를 못 찾았어");
console.log("정상적으로 삭제 완료");
});
데이터 수정
const updateSql = "UPDATE products SET name = ?, number = ?, WHERE id = ?";
mysqlConnect.query(updateSql, ["jaka123", "456", "3"], (err) => {
if(err)
console.log(err);
console.log("데이터 수정 완료");
});
-- 기본 인코딩 방식은 utfmb4
-- mb4 : most bytes 4 : 4byte씩 사용하는 utf8 문자 집합으로 유니코 문자를 지원하겠다.
-- utfmb4 : 4byte씩 사용하는 utf8 문자 집합으로 유니코드 문자를 지원하겠다. (전세계 문자 + 이모티콘 사용 가능)
-- general : 비교 정렬 규칙을 정의
-- ci : 대소문자 구분 안함.
-- JAKA 라는 이름의 데이터베이스를 만들겠다
CREATE DATABASE JAKA DEFAUTL CHARACTER SET utfmb4 COLLATE utf8mb4_general_ci;
2. Database 보기
SHOW DATABASES;
3. Database 삭제
-- JAKA 라는 이름의 데이터베이스 삭제
DROP DATABASE JAKA;
4. Database 사용
-- JAKA 라는 데이터베이스를 사용하겠다.
USE JAKA;
5. 현재 사용중인 데이터베이스의 테이블 내용을 확인
SHOW TABLES;
6. 테이블 생성
-- CREATE TABLE 테이블 이름 (컬럼이름 데이터타입 옵션)
-- AUTO_INCREMENT : 자동으로 증가한다. (인덱스 형태를 의미)
-- 테이블에 열이 하나씩 추가될 때마다 증가
-- PRIMARY KEY : 고유한 키 하나만 존재할 수 있다
-- VARCHAR : 256Byte의 가변 데이터 (우리가 20자까지 사용을 안하면 알아서 맞춘다.)
CREATE TABLE store(id INT AUTO_INCREMENT PRIMARY KEY, tel VARCHAR(20));
7. 테이블의 필드명 확인
-- store라는 테이블의 필드를 보여준다
DESC store;
8. 테이블 값 추가
-- NOT_NULL : NULL 값이 들어갈 수 없다. 즉, 빈 값을 넣을 수 없다는 의미다
-- DEFAULT : 입력을 안하면 남자로 기본값이 들어간다
CREATE TABLE user(
user_id VARCHAR(20) PRIMARY KEY,
user_pw VARCHAR(20) NOT_NULL,
user_name VARChAR(10) NOT_NULL,
gender CHAR(4) DEFAULT '남자',
date DATETIME DEFAULT now()
);
-- 괄호의 순서대로 값을 할당하겠다.
-- VALUES(추가할 데이터 내용들)
-- PRIMARY KEY는 같은 값이 포함되면 데이터가 들어가지 않는다.
INSERT INTO user(user_id, user_pw, user_name) VALUES ('userid0', '123', 'jaka1');
9. 조회
-- * : 모든 필드를 의미
-- user : 조회하고 싶은 테이블
SELECT * FROM user;
-- 조회를 할 때 원하는 필드의 내용을 찾아서 조회
-- WHERE 조회할 속성을 정해줄 수 있다.
-- user_id가 userid0 인 값의 모든 필드명 조회
SELECT * FROM user WHERE user_id = 'userid0';
-- user_id, user_name 필드명을 user_name이 jaka1에서 조회
SELECT user_id, user_name FROM user WHERE user_name = 'jaka1;
-- 테이블의 값 오름차순 내림차순 조회
-- DESC : 필드명 기준 내림차순 / ASC : 필드명 기준 오름차순
SELECT * FROM 이름 ORDER BY 필드이름 DESC/ASC;
-- 테이블의 값을 조회할 때 시작 데이터 조회
-- A로 시작하는 데이터를 가지고 있는 row 들을 조회
SELECT * FROM 테이블이름 WHERE 필드 LIKE 'A%';
-- A로 끝나는 데이터를 가지고 있는 row들을 조회
SELECT * FROM 테이블이름 WHERE 필드 LIKE '%A';
10. 값 수정
-- UPDATE 테이블명 SET 변경할필드='값' WHERE 필드명='필드ID';
UPDATE user SET gender='남자', user_name='jakas' WHERE user_id='userid0';
11. 테이블 삭제
-- user 테이블에서 user_id가 userid0 인 값을 삭제
DELETE FROM user WHERE user_id='userid0';
12. 테이블 이름 바꾸기
ALTER TABLE 테이블이름 RENAME 변경이름;
13. 컬럼의 이름, 데이터 타입 바꾸기
ALTER TABLE 이름 CHANGE 기존컬럼이름 새로운컬럼이름 데이터타입;
14. 컬럼의 타입만 변경
ALTER TABLE 테이블명 MODIFY 컬럼의이름 수정할데이터타입;
15. 필드를 제거
ALTER TABLE 테이블이름 DROP 필드이름;
16. 필드 추가
-- 필드 추가
-- 필드 맨뒤로 추가
ALTER TABLE 이름 ADD 필드이름 데이터타입
-- 필드 맨앞 추가
ALTER TABLE 이름 ADD 필드이름 데이터타입 first;
우리가 많이 쓰는 HTML은 정적인 언어다. 정적인 페이지는 주어진 기능만 사용할 수 있는 한계가 있고
직접 기능을 추가할 수 없다. (자바스크립트를 사용해야만 한다.)
반면에 템플릿 엔진은 자바스크립트를 사용하여 HTML을 렌더링 할 수 있다.
HTML 과 문법이 거의 흡사하지만 자바스크립트의 문법이 들어갈 수 있다는 특징이 있다.
(서버측에서 html을 만들어서 응답해주는 것이다.)
템플릿 엔진에는 여러가지가 있는데 우리가 알아볼 것은 그 중 EJS다.
2. EJS 설치 및 사용 방법
ejs 설치
npm i ejs
문법은 다음과 같다.
<% JS 코드 %> <%= 변수의 내용 %>
문법이 다소 난해하다. 밑에서 어떻게 사용하는지 예를 들어보자
server.js
// ejs를 require 하는 구문이 있어서 설치를 해야한다.
const express = require('express');
const app = express();
const path = require('path');
// set : server 객체 안에 있는 내용을 수정하겠다.
// view engine을 ejs를 사용하겠다.
app.set('view engine', 'ejs');
// Template가 있는 디렉토리
app.set('views', path.join(__dirname, 'views'));
const boardList = [
{id : 1, name : "jaka"},
{id : 2, name : "jaka2"},
{id : 3, name : "jaka3"},
{id : 4, name : "jaka4"}
]
const title = '페이지 제목';
app.get('/', (req, res) => {
// 페이지에서 변수를 사용해서 html 페이지를 완성시켜서 보여줄 것
// 문자열 파싱을 해서 스크립트 변수 내용을 포함한 완성된 html을 응답해준다
// render : view enigine ejs를 사용할 때 페이지를 완성시켜서 응답
// 문자열을 파싱해서 html을 완성시켜서 최종적으로 만들어진 html을 응답해줌
res.render('main', {boardList, title});
});
app.listen(3000, () => {
consoloe.log('server on~');
});