HTML 요소를 반환하는 함수나 클래스와 같다고 생각해도 된다. 따라서, 컴포넌트는 독립적이고, 재사용 가능한 코드의 조각이다.
컴포넌트의 종류로는, 1. 함수형 컴포넌트, 2. 클래스형 컴포넌트가 있다.
💡 함수형 컴포넌트
간단한 예로, 함수형 컴포넌트 형태를 보자.
function Introduce() {
return <h2>Hi, I am elice!</h2>;
}
ReactDOM.render(<Introduce />, document.getElementById('root'));
💡 클래스형 컴포넌트
함수형 컴포넌트와 비교했을 때, 약간 구조만 다른 정도다. 다만, class 선언 시, React.Component의 메소드들을 사용하기 위해, extends를 이용해, React.Component를 상속 render( ) 함수안에, 반환 할, HTML 요소를 return 으로 반환 간단한 예로, 클래스형 컴포넌트 형태를 보자.
class Introduce extends React.Component {
render() {
return <h2>Hi, I am elice!</h2>;
}
}
ReactDOM.render(<Introduce />, document.getElementById('root'));
💡 이 둘은 각각, 언제 사용하는가 ?
함수형 컴포넌트
단순히 HTML UI를 반환하는 간단한 자바스크립트 함수로 자주 사용한다.
단순히, 데이터를 받고, 렌더링 하면 끝이지 때문에, 비상태형 컴포넌트라고도 한다.
클래스 컴포넌트
클래스 컴포넌트는, "상태(State)"를 구현할 때 사용한다.
여기서, "상태(State)"란, React의 State를 의미하며, 쉽게 말하면, 컴포넌트의 현재 저장된 값
이런, "상타(State)"를 가지는, 클래스 컴포넌트를, 다른 말로, 상태형 컴포넌트라고도 한다.
HTML을 반환하는 render( ) 메소드가 구현되어, 복잡한 UI 로직을 구현할 때 클래스형 컴포넌트를 사용한다.
특히, State를 사용할 때, 반드시(?) 클래스형 컴포넌트로 구현이 되어야 한다.
그러나, 기술이 발달 되면서, 이제는, 사실, 클래스 컴포넌트에서만, 다룰 수 있던, 컴포넌트의 상태(State)를, 함수형 컴포넌트에서도 다룰 수 있게 되었고, 그러한 기술을 우리는, "훅(hook)" 이라고한다.
이것은, 뒤에서 설명하려고 한다. ( 아주 중요하기 때문 ! )
그리고, 요즘은 사실, 클래스형 컴포넌트보단, hook을 이용한, 함수형 컴포넌트로 React를 구현하는 것이 추세라고 한다.
JSX는 자바스크립트 XML의 약자. 즉, JSX는 자바스크립트를 확장한 문법이며, 그런 만큼, 자바스크립트와 사용법이 많이 비슷하다. HTML을 React에서 쉽게 쓰기 위해 사용한다.
React는 JSX 문법을 이용해 마크업 언어와 코드의 로직을 따로 분리하지 않고, 두 가지를 포함한 "컴포넌트"를 사용
💡 표현식
JSX에서는 "중괄호( { } )"를 이용해, 사용 가능한 표현식들이 있다.
먼저, 중괄호를 이용해, HTML 내에 변수를 표현할 수 있다.
const name = 'elice';
const element = <h1> Hello, {name}! </h1>;
중괄호를 이용해, 함수 표현식을 넣는 것도 가능하다.
function greeting(){
return "Hello, elice!";
}
const element = <h1>{greeting()}</h1>;
함수 내에서 표현식을 적용할 수도 있다.
function formatGreeting(name){
return "Hello" + ' ' + name;
}
function getGreeting(user) {
return <h1>Hello, {formatGreeting("elice!")}!</h1>;
}
💡 속성
큰 따옴표를 이용해 JSX의 속성을 지정할 수 있다.
const element = <a href = "https://kdt.elice.io/explore">엘리스로 이동</a>;
💡 자식 정의
자식 태그가 여러개 포함된 코드를 저장하기 위해서는, 자식 태그를 부모 태그로 감싸야 한다.
const element = (
<div>
<h1>Hello,</h1>
<h2>elice!</h2>
</div>
);
// <div> = 부모 태그
// <h1>,<h2> = 자식 태그
모든 태그는 반드시 닫혀야 한다. 다만, 원래 태그 이름을 맞춰서 </input> 처럼 닫아야 하지만 이름은 생략하고 />만 이용해서 닫아도 괜찮다.
const element = <input type="text" />;
💡 객체 표현
React.createElement( ) 메소드를 이용하면, JSX 문법을 이용하지 않고, 객체로 표현할 수 있다. 두 코드는 문법이 다르지만, 같은 내용을 담고 있다.
HTML 직접생성
const element = (
<h1 className="greeting">
Hello, world!
</h1>
);
React.createElement( ) 로 생성
const element = React.createElement(
'h1',
{className: 'greeting'},
'Hello, world!'
);
📝 엘리먼트 렌더링
Element ( 엘리먼트 ) : React 앱의 가장 작은 단위, 컴포넌트(Component의 구성요소)
쉽게 말하면, HTML 요소라고 할 수 있다.
Rendering( 렌더링 ) : 이러한 element를 화면에 그리는 것
💡 ReactDOM과 렌더링
React는 가상(Virutal) DOM과 실제로, 표시되는 DOM을 유지한다.
React는 실제 DOM을 추상화하여, 가상 DOM에 만들어두고, 데이터가 업데이트되면 한 번에 렌더링한다.
결과적으로, 계속해서 DOM을 렌더링하는 것보다 속도가 빠르다.
ReactDOM.render( ) : 렌더링 함수
HTML 파일 안에 Id가 root인 요소가 있다고 해보자.
<div id="root"></div>
해당 HTML에 텍스트를 넣기 위해, ReactDOM.render( )을 이용해, 다음과 같이 렌더링 한다.
const element = <h1>Hello, elice</h1>;
ReactDOM.render(element, document.getElementById('root'));
// ReactDOM에 렌더링 할꺼다. element를, id = root 인 요소에다가 ~
💡 엘리먼트 업데이트
엘리먼트는 한 번 생성되면, 수정이 불가능한 불변 객체이다.
값을 변경하고 싶으면, 새로운 엘리먼트를 만들어 업데이트 해야 한다.
만약, 시간을 출력하는 기능을 구현하고 싶다면, 매 초마다 렌더링을 해줘야 할 것이다.
function tick() {
const element = (
<div>
<h1>{new Date().toLocaleTimeString()}</h1>
</div>
);
ReactDOM.render(element, document.getElementById('root'));
}
setInterval(tick, 1000);
Date 객체의 toLocaleTimeString( ) 메소드를 이용하면, 시간을 반환해주는데, 실제로 시간이 변하는 것을 확인하기 위해서는 setInterval( ) 콜백을 이용해 tick을 계속 호출해야한다. setInterval( )의 매개변수인 1000은 1초를 의미한다.
/*
다음은 GroceryList 라는 컴포넌트는
이후 React DOM 라이브러리에 의해 "랜더링(Rendering)"되어 화면에 출력될 수 있다.
*/
function GroceryList(props) {
return (
<div>
<h1>Grocery List</h1>
<ul>
<li>Milk</li>
<li>Bread</li>
<li>Eggs</li>
</ul>
</div>
)
};
💡 앱에서 기능이 분할되는 방식
JS는 앱의 기능 또는 UI의 요소를 분할하는 방법에 대한 특별한 요구사항이 없다. 기본적인 출력은 HTML 파일에 정의한다.
그런 다음, 리스너 내부에서, 먼저 이전과 동일한 방법을 사용하여, 입력 상자의 값을 가져올 수 있을 것이다. 그런 다음, 식료품 목록에 새 항목을 추가하려면, DOM에서 목록을 찾고, 추가 할 새 항목을 만든 다음, 마지막으로 목록 끝에 추가해야 할 것이다. ( 이렇게만 봐도, 상당히 복잡함을 알 수 있다. )
이런 태그를 서로 조합하면, 사용자가 내용을 채우고, 웹사이트나 어플리케이션에 제출할 수 있다.
그리고, 서버는 그런 데이터를 조작해서 생산성있고, 상호작용이 가능한 무언가를 만들 수 있을 것이다.
📝 <button>
클릭 가능한 버튼을 담당한다. 버튼은 양식 내부는 물론, 간단한 표준 버튼 기능이 필요하면 어디든 배치할 수 있다.
📢 예시
<button name="button">눌러보세요</button>
🔊 결과
📌 필요시 추가정보
📝 <form>
정보를 제출하기 위한 대화형 컨드롤을 포함하는 문서 구획을 담당한다.
📢 예시
<!-- Form which will send a GET request to the current URL -->
<form>
<label>Name:
<input name="submitted-name" autocomplete="name">
</label>
<button>Save</button>
</form>
<!-- Form which will send a POST request to the current URL -->
<form method="post">
<label>Name:
<input name="submitted-name" autocomplete="name">
</label>
<button>Save</button>
</form>
<!-- Form with fieldset, legend, and label -->
<form method="post">
<fieldset>
<legend>Title</legend>
<label><input type="radio" name="radio"> Select me</label>
</fieldset>
</form>
🔊 결과
📌 필요시 추가정보
📝 <input> 태그
웹 기반 양식에서 사용자의 데이터를 받을 수 있는 대화형 컨들롤을 담당한다. 사용자에 따라서 다양한 종류의 입력 데이터 유형과 컨트롤 위젯이 존재한다. 입력 유형과 특성의 다양한 조합 가능성으로 인해, <imput>요소는 가장 강력하면서도 복잡한 태그 중 하나다.
<input> 태그는 속성 및 옵션이 정말 많으니, 필요시 참고문서를 꼭 확인하자.
📢 예시
<!-- A basic input -->
<input type="text" name="input" value="Type here">
<!-- A common form that includes input tags -->
<form action="getform.php" method="get">
<label>First name: <input type="text" name="first_name" /></label><br />
<label>Last name: <input type="text" name="last_name" /></label><br />
<label>E-mail: <input type="email" name="user_email" /></label><br />
<input type="submit" value="Submit" />
</form>
<datalist> : 다른 컨트롤에서 고를 수 있는 가능한, 혹은 추천하는 선택지를 나타내는 <option>요소 여럿을 담는다. <label> : 웹 기반 양식에서 사용자의 데이터를 받을 수 있는 대화형 컨트롤을 생성한다. <fieldset> : 웹 양식의 여러 컨트롤과 레이블(<label>)을 묶을 때 사용합니다.
<article> 태그는 독립적인 자체에 포함된 내용을 담당한다. 말 그대로, 기사는 그 자체로 의미가 있어야하며, 나머지 웹 사이트와 독립적으로 배포 할 수 있어야 한다.
<article> 요소를 사용할 수 있는 위치의 예
포럼 게시물
블로그 게시물
신문 기사
📢 예시
<article>
<h2>기사 1</h2>
<p>김 아무개씨가 오늘 아침 식사를 했다고 합니다. 아주 맛있었다고 합니다.</p>
</article>
<article>
<h2>기사 2</h2>
<p>김 아무개씨가 오늘 점심 식사를 했다고 합니다. 아주 별로였다고 합니다.</p>
</article>
<article>
<h2>기사 3</h2>
<p>김 아무개씨가 오늘 저녁 식사를 했다고 합니다. 아주 아주 맛있었다고 합니다.</p>
</article>
🔊 결과
기사 1
김 아무개씨가 오늘 아침 식사를 했다고 합니다. 아주 맛있었다고 합니다.
기사 2
김 아무개씨가 오늘 점심 식사를 했다고 합니다. 아주 별로였다고 합니다.
기사 3
김 아무개씨가 오늘 저녁 식사를 했다고 합니다. 아주 아주 맛있었다고 합니다.
📝 <header> 태그
<header> 태그는 일반적으로, 소개 내용이나, 탐색 링크의 집합에 대한 컨테이너를 담당한다. <header> 태그는 일반적으로
<i> : 텍스트에서 어떤 이유로 주위와 구분해야하는 부분을 나타낸다. <em> : 텍스트 강세를 나타낸다. <em> 중첩하면 더 큰 강세를 뜻한다.
📢 예시
<p>Get out of bed <em>now</em>!</p>
<p>We <em>had</em> to do something about it.</p>
<p>This is <em>not</em> a drill!</p>
<p>I looked at it and thought <i>This can't be real!</i></p>
🔊 결과
Get out of bed now!
We had to do something about it.
This is not a drill!
I looked at it and thought This can't be real!
📝 구분선 태그 & 줄 바꿈 태그
<hr> : 수평선을 삽입 할 수 있는 태그, 종료태그(/)가 없어도 된다. <br> : 줄바꿈을 삽입 할 수 있는 태그, 종료태그가 없어도 된다.
<hr> <br>
🔊 결과
사이에 <br> 태그로 공백 넣은 것입니다.
📝 목록 태그
<ul> : 순서 없는 목록 (unordered list) <ol> : 순서 있는 목록 (ordered list) <dl> : 정의 목록 (definition list) <li> : 위에 큰 3가지 목록 스타일 안에 각각의 list 행
📢 예시
<ul>
<li>ul 리스트 li 1</li>
<li>ul 리스트 li 2</li>
</ul>
<ol>
<li>ol 리스트 li 1</li>
<li>ol 리스트 li 2</li>
</ol>
<ul>
<li>dl 리스트 li 1</li>
<li>dl 리스트 li 2</li>
</ul>
🔊 결과
ul 리스트 li 1
ul 리스트 li 2
ol 리스트 li 1
ol 리스트 li 2
dl 리스트 li 1
dl 리스트 li 2
📝 컨데이너 태그
<div> : 아무의미 없는 태그, 어떤 컨텐츠들끼리 목적에 따라 묶어야 할 때 사용한다. ( 줄바꿈 O = block 요소 )
<span> : 아무런의미 없는 태그, <div>와 같이, 어떤 목적에 따라 묶어야 할 때 사용한다. ( 줄바꿈 X = inline요소 )
📢 예시 <div> ... 컨텐츠1 .... </div>
<div> ...컨텐츠2... </div>
<p><span>Some text</span></p>
📝 테이블 태그
<table> : 테이블 컨테이너이며, 테이블의 시작과 끝에 삽입 <caption> : 테이블의 제목 <thead> : 테이블의 헤드 셀 그룹 <tbody> : 테이블의 데이터가 들어가는 셀 그룹 <tfoot> : 테이블의 바닥 셀 그룹
<tr> : 행 그룹, td와 th를 포함 <th> : 제목 셀 <td> : 데이터 셀
📢 예시
<table><caption>테이블 제목</caption>
<thead>
<tr>
<th>thead 제목 셀</th>
<td>thead 데이터 셀1</td>
<td>thead 데이터 셀2</td>
</tr>
</thead>
<tbody>
<tr>
<th>thead 제목 셀</th>
<td>thead 데이터 셀1</td>
<td>thead 데이터 셀2</td>
</tr>
</tbody>
<tfoot>
<tr>
<th>thead 제목 셀</th>
<td>thead 데이터 셀1</td>
<td>thead 데이터 셀2</td>
</tr>
</tfoot>
</table>
🔊 결과
테이블 제목
thead 제목 셀
thead 데이터 셀1
thead 데이터 셀2
tbody 제목 셀
tbody 데이터 셀1
tbody 데이터 셀2
tfoot 제목 셀
tfoot 데이터 셀1
tfoot 데이터 셀2
📝 하이퍼링크 태그
<a href="" target=""> : href 속성을 이용해 URL 또는 HTML페이지로 이동가능하다.
target 옵션
_blank : 새 윈도우 _self : 현재 윈도우 _parent : 부모 윈도우 _top : 브라우저 윈도우
📌 UPDATE(PUT)와 DELETE(DLEDTE)는 앞선, CREATE(POST), READ(GET)과 달리, Ajax를 이용해서 구현되기도 한다.
📝 Ajax : 비동기식(Asynchronous) JavaScript + XML 이다.
Ajax 는 REST API를 손쉽게 구현하기 위해 사용되는 "프레임워크"이며, html 파일에서 간단히 사용하는 방법을 해보자. ( 이번에는, html 파일을 더, 주의깊게 보자. ( Ajax 부분 ) )
# Ajax_Example.py
from flask import Flask, render_template, request, jsonify # Flask의 내장된 jsonify = json.dump() 와 같은 기능이다. json 형태로 데이터 반환
app = Flask(__name__)
board = [] # 임시 DB 개념 (사실,리스트)
# root
@app.route("/")
def index():
return render_template("ajax_index.html", rows=board)
@app.route("/ajax", methods=["POST"])
def ajax():
data = request.get_json() # request.get_json() = POST 요청을 통해 얻은 데이터 -> json 형식으로 얻기 위한 메소드
board.append(data)
return jsonify(result="success", result2=data) # json_dumps({}) 와 기능은 같다.
if __name__ == '__main__':
app.run()
<!--ajax_index.html-->
<html>
<head>
<script src="https://code.jquery.com/jquery-latest.min.js"></script>
</head>
<body>
<p id="example">AJAX</p>
<input type="text" id="id1" placeholder="id">
<input type="text" id="name1" placeholder="name">
<input type="text" id="context1" placeholder="context">
<input type="button" id="execute" value="execute">
<script>
$('#execute').click(function () {
var id = $('#id1').val();
var name = $('#name1').val();
var context = $('#context1').val();
var postdata = {
'id': id, 'name': name, 'context': context
}
// ajax 형식으로 -> ajax example.py로 데이터 전송
$.ajax({
type: 'POST',
url: '{{url_for("ajax")}}',
data: JSON.stringify(postdata), // 서버로 데이터를 넘길때는, JSON.stringify(데이터)로 String형식으로 넘겨준다.
dataType: 'JSON',
contentType: "application/json",
success: function (data) {
alert('성공! 데이터 값:' + data.result2['id'] + " " + data.result2['name'] + " " + data.result2['context'])
},
error: function (request, status, error) {
alert('ajax 통신 실패')
alert(error);
}
})
})
</script>
<table border=1 width="600">
<thead>
<td>목차</td>
<td>이름</td>
<td>내용</td>
</thead>
{% for row in rows %}
<tr>
<td>{{ loop.index }}</td>
<td>{{ row['name'] }}</td>
<td>{{ row['context'] }}</td>
</tr>
{% endfor %}
</table>
</body>
</html>