SPA(Single Page Application) : 하나의 화면 (Index.html)을 가지고 애플리케이션의 모든 요청을 처리하는 방식
MPA(Multi Page Applicaion) : 여러 개이 파일을 번갈아가면서 애플리케이션이 요청을 처리하는 방식
react 는 싱글 페이지 애플리케이션 개발을 위한 Front End JavaScript Framework
HTML 문서를 서버에서 처리한 결과 데이터와 결합해서 출력해주는 소프트웨어
동적인 HTML 문서를 만들기 위해서 필요
서버 측, 클라이언트 측에 모두 필요하다
서버 측 Template Engine 은 HTML을 생성해 내고, Front End 측은 DOM 객체의 조합을 만들어 낸다
angular, react, vue 는 Front End 에서 동작하는 템플릿 엔진
페이스 북에서 만든 오픈 소스 자바스크립트 프레임 워크
유저 인터페이스를 생성하는 것이 목적
Virtual DOM 을 이용해서 랜더링을 수행하고 JSX 문법을 이용해서 작성
Virtual DOM 은 게임 엔진에서 랜더링 할 때 사용하는 방식으로 화면을 다시 출력해야 할 때 전체를 다시 출력하는 것이 아닌, 변경된 부분만 재출력하는 방식을 사용
Virtual DOM 이 HTML 의 실제 DOM 보다 빠른 이유는 DOM 자체를 출력하는 속도는 HTML의 실제 DOM 이 빠르지만,
실제 DOM은 변화가 생기면 DOM을 생성하고 CSS를 다시 적용해서 출력하는 형태로 동작하기 때문에 이전과 동일한 CSS 내용이나 레이아웃을 읽어서 출력하지만 Virtual DOM 을 사용하게 되면 디자인은 그대로 두고 데이터만 변경하는 형태로 동작을 하기 때문에 빠름
React 는 오로지 '화면 출력' 만 담당
데이터를 가져오는 부분이나 상태 관리에 대한 부분은 별도의 라이브러리를 사용
node.js 설치 - react에서 사용하는 webpack 이나 babel 이 자바스크립트 런타임인 node.js를 사용
webpack : 프로젝트에서 사용된 파일을 분석해서 웹 문서 파일로 변환하는 Module Bundler
babel : ECMA 2015(ES6) 이상의 코드를 javascript 엔진에서 사용할 수 있도록 번역해주는 javascript 트랜스 컴파일러
IDE - Visual Studio
typescript 컴파일러 설치 및 확인
scoop : 윈도우 사용자가 brew 나 apt 같은 프로그램을 사용하고자 하는 경우
🔎 자바 스크립트는 자료형을 작성하지 않음 - 컴파일 시 에러를 잡아내지 못함
let a = 10
🔎 타입 스크립트는 자료형을 명시
a:number = 10
# vscode 의 터미널에서
$ npm create react-app testapp
cd testapp
npm istall
Public 디렉토리 : 정적인 파일을 저장하기 위한 디렉토리
manifest.json : 앱에 대한 정보
robots.txt : 검색 로봇에게 사이트 및 웹 페이지를 수집할 수 있도록 허용하거나 제한하는 국제 권고안
src 디렉토리
package.json : 노드 애플리케이션의 설정 파일
package-lock.json : 라이브러리의 의존성을 자세히 출력하는 파일 - 없어도 됨
README.md : 마크 다운 파일
개발 모드로 실행 : 디렉토리로 이동하여 npm run start(yarn 으로 생성한 경우 yarn start 가능)
localhost:3000 으로 확인 가능 - react 로고가 보일 것
document.createElement(태그이름[, 옵션])
index.js 파일에서 사용됨
자바스크립트에 XML을 추가한 확장형 문법
XML이나 HTML은 동적인 데이터를 가지고 DOM을 생성하지 못함
동적인 데이터를 가지고 DOM을 생성하고자 할 때는 JavaScript의 도움을 받아야 함
JavaScript와 XML을 혼용해서 사용할 수 있는 문법으로 코드가 번들링될 때 babel-loader를 사용해서 자바스크립트 구문으로 변경해서 실행
장점
규칙
주석
주석
{/* 주석 내용 /}
만들거나 태그 안에서는 // 나 / 주석 /을 이용해서 작성이 가능한데 이 경우 닫는 것은 다음 줄에 입력이 되어야 함
<img // 주석
/>
모든 태그는 반드시 닫아야 하고 순서대로 닫아야 함
모든 요소는 반드시 하나의 태그 안에 배치가 되어야 함
하나의 컴포넌트에서 root는 한 개
import logo from './logo.svg';
import './App.css';
import React, {Fragment} from 'react';
function App() {
const message = "자바스크립트의 표현식";
return (
<>
<h1>React App</h1>
<h2>{message}</h2>
</>
);
}
export default App;
import logo from './logo.svg';
import './App.css';
import React, {Fragment} from 'react';
function App() {
const message = "자바스크립트의 표현식";
let condition = false;
let data = null;
return (
<>
<h1>React app</h1>
<h2>{message}</h2>
<p>{condition ? "참" : "거짓"}</p>
<p>{condition && "참"}</p>
<p>{data}</p>
</>
);
}
export default App;
Camel Case
클래스는 대문자로 시작하고 속성과 메서드는 소문자로 시작하는데,
두 번째 단어의 시작은 대문자로 명명하는 방식
Snake Case
상수의 이름은 모두 대문자로 표기
헝거리언 표기법
접두어를 붙이는 방식으로 데이터의 범위와 자료형에 대한 접두어를 사용하는 방식
g_자료형
m_
_
파이썬에서는 _를 사용하면 안됨
import logo from './logo.svg';
import './App.css';
import React, {Fragment} from 'react';
function App() {
const style = {
backgroundColor:"black",
color:"aqua",
fontSize:"48px",
fontWeight:"bold",
padding:16
}
return (
<>
<h1 style={style}>React App</h1>
<h2 className='react'>React App</h2>
</>
);
}
export default App;
MVC(Model View Controller) : 기능 별로 나누어서 구현
Model : 데이터베이스에 작업을 수행하는 Persistance 계층 과 Bussiness Logic을 수행하는 Service 계층을 합친 것
View : 화면 출력 부분
Controller : Model 과 View 사이를 연결
MVC 구조의 View를 독립적으로 구성한 개체
Component를 여러 개 조합해서 하나의 화면을 생성
데이터의 변경이나 이벤트가 발생하면 화면을 리랜더링 하지 않고 Component를 리랜더링 하는 개념
여러가지 기능을 소유하고 있기 때문에 단순한 View 와는 다르다
서버 사이드 템플릿 엔진은 데이터를 출력하는 용도 외에는 사용할 수 없는데 Component 는 여러 가지 기능을 내장한다
함수형 컴포넌트 : 함수를 가지고 생성
클래스형 컴포넌트 : 클래스를 가지고 생성
❓ 함수가 클래스의 인스턴스 보다는 가볍고, 클래스가 함수보다는 안전하다
최근에는 속도 때문에 함수형 컴포넌트를 권장함 - Life Cycle(수명주기) 를 이용하는 경우가 아니라면 함수형 컴포넌트를 사용
기본 틀 - MyComponent.jsx
import React, {Component} from "react";
class MyComponent extends Component{
render(){
return(
<div>
컴포넌트 첫번째
</div>
)
}
}
export default MyComponent
App.js
import logo from './logo.svg';
import './App.css';
import React, {Fragment} from 'react';
import MyComponent from './MyComponent';
function App() {
return (
<MyComponent />
);
}
export default App;
MyComponent.jsx
import React, {Component} from "react";
class MyComponent extends Component{
render(){
const isLoading = true;
if(isLoading){
return <p>Loading...</p>
}
return(
<div>
컴포넌트 첫번째
</div>
)
}
}
export default MyComponent
컴포넌트를 만들 때 이름 = 값의 형태로 설정
클래스 형 컴포넌트에서는 this.props.name 이라는 속성으로 내부에서 사용이 가능
사용하는 이유는 상위 컴포넌트에서 하위 컴포넌트에게 데이터를 전달할 목적
컴포넌트 내부에서 수정할 수 없다.
props 값이 수정되면 자동으로 리렌더링 된다.
App.js 에서 MyComponent 에서 출력하는 부분을 수정
import logo from './logo.svg';
import './App.css';
import React, {Fragment} from 'react';
import MyComponent from './MyComponent';
function App() {
return (
<MyComponent name ="lee" />
);
}
export default App;
import React, {Component} from "react";
class MyComponent extends Component{
render(){
console.log(this.props.name);
return(
<div>
컴포넌트 첫번째 : {this.props.name}
</div>
)
}
}
export default MyComponent
MyComponent.jsx - data 변수
import React, {Component} from "react";
class MyComponent extends Component{
render(){
console.log(this.props.name);
let data = this.props.name;
return(
<div>
컴포넌트 첫번째 : {data}
</div>
)
}
}
export default MyComponent
MyComponent.jsx
class MyComponent extends Component{
render(){
console.log(this.props.name);
//props 의 값을 컴포넌트 내부에서는 변경할 수 없음
//this.props.name = "steven"
//props 의 값을 변경하고자 하면 다른 변수를 생성해서 수행해야 한다
let data = this.props.name;
data = "steven";
return(
<div>
컴포넌트 첫번째 : {data}
</div>
)
}
}
export default MyComponent
props로 전달된 데이터는 함수의 매개변수가 된다.
MyComponent.jsx 파일을 수정해서 함수형 컴포넌트로 변경
MyComponent.jsx
import React, {Component} from "react";
const MyComponent = () => {
return(
<div>함수형 컴포넌트 </div>
)
}
export default MyComponent
MyComponent.jsx
import React, {Component} from "react";
const MyComponent = (props) => { //매개변수로 props 입력
return(
<div>함수형 컴포넌트 : {props.name} </div>
)
}
export default MyComponent
App.js
import logo from './logo.svg';
import './App.css';
import React, {Fragment} from 'react';
import MyComponent from './MyComponent';
function App() {
return (
<MyComponent name ="lee" />
);
}
export default App;
App.js
import logo from './logo.svg';
import './App.css';
import React, {Fragment} from 'react';
import MyComponent from './MyComponent';
function App() {
return (
<MyComponent/>
);
}
export default App;
MyComponent.jsx
import React, {Component} from "react";
const MyComponent = (props) => {
return(
<div>함수형 컴포넌트 : {props.name} </div>
)
}
MyComponent.defaultProps = {
name : "기본값 설정"
}
export default MyComponent
App.js
import logo from './logo.svg';
import './App.css';
import React, {Fragment} from 'react';
import MyComponent from './MyComponent';
function App() {
return (
<>
<MyComponent>태그 안의 내용1</MyComponent>
<MyComponent>태그 안의 내용2</MyComponent>
</>
);
}
export default App;
MyComponent.jsx
import React, {Component} from "react";
const MyComponent = (props) => {
return(
<>
<div>함수형 컴포넌트 : {props.name} </div>
<div>태그 안의 내용 : {props.children}</div>
</>
)
}
MyComponent.defaultProps = {
name : "기본값 설정"
}
export default MyComponent
App.js
import logo from './logo.svg';
import './App.css';
import React, {Fragment} from 'react';
import MyComponent from './MyComponent';
function App() {
return (
<>
<MyComponent>태그 안의 내용1</MyComponent>
<MyComponent>태그 안의 내용2</MyComponent>
</>
);
}
export default App;
MyComponent.jsx
import React, {Component} from "react";
const MyComponent = (props) => {
const {name, children} = props; //구조 분해 할당 내용
return(
<>
<div>함수형 컴포넌트 : {props.name} </div>
<div>태그 안의 내용 : {props.children}</div>
</>
)
}
MyComponent.defaultProps = {
name : "기본값 설정"
}
export default MyComponent
MyComponent.jsx
import React, {Component} from "react";
const MyComponent = ({name,children}) => {
//const {name, children} = props;
return(
<>
<div>함수형 컴포넌트 : {name} </div>
<div>태그 안의 내용 : {children}</div>
</>
)
}
MyComponent.defaultProps = {
name : "기본값 설정"
}
export default MyComponent
MyComponent.jsx
import React from 'react';
import PropTypes from 'prop-types';
const MyComponent = ({name, year, children}) => {
return(
<>
<div>함수형 컴포넌트: {name}</div>
<div>태그 안의 내용: {children}</div>
<div>년도: {year}</div>
</>
)
}
MyComponent.propTypes = {
name:PropTypes.string
}
MyComponent.defaultProps = {
name:"기본값",
year:PropTypes.number.isRequired
}
export default MyComponent;
App.js
import './App.css';
import React from 'react';
import MyComponent from './MyComponent';
function App() {
return (
<MyComponent name='adam' year={2023}>태그 안의 내용</ MyComponent>
);
}
export default App;
array : 배열
bool : boolean
func : 함수 - 자바스크립트에서는 함수도 하나의 자료형
number : 숫자
object : 객체
string : 문자열
node : 화면에 출력될 수 있는 모든 것
element : react 요소
any : 모든 자료형
App.js
import MyComponent from './MyComponent';
function App() {
return (
<>
<MyComponent name="아담" favoriteNumber={3} children="my son"/>
</>
)
}
export default App;
MyComponent.jsx
import React, {Component} from 'react';
import PropTypes from 'prop-types';
class MyComponent extends Component {
render() {
const { name, favoriteNumber, children } = this.props; // 비구조화 할당
return (
<div>
안녕하세요, 제 이름은 {name} 입니다. <br />
children 값은 {children}
입니다.
<br />
제가 좋아하는 숫자는 {favoriteNumber}입니다.
</div>
);
}
}
MyComponent.defaultProps = {
name:'기본 이름'
}
MyComponent.propTypes = {
name:PropTypes.string,
favoriteNumber:PropTypes.number.isRequired
}
export default MyComponent;
All React Component must act like pure functions with respect to their props
모든 react component는 그들의 props에 관해서는 Pure 함수 같은 역할
props 는 상위 컴포넌트가 하위 컴포넌트에게 넘겨주는 데이터 - 데이터를 상위 컴포넌트에서 만들기 때문에 하위 컴포넌트에서 변경하지 못하도록 함
state 는 컴포넌트 내부에서 만드는 데이터로 읽기와 수정 모두 가능
초기화
get
set
App.js
import MyComponent from './MyComponent';
import ClassComponent from './ClassComponent';
function App() {
return (
<>
<ClassComponent/>
<MyComponent name="아담" favoriteNumber={3} children="my son"/>
</>
)
}
export default App;
ClassComponent.jsx
import React, { Component } from "react";
class ClassComponent extends Component{
//생성자
constructor(props){
super(props);
this.state = {
number:0
}
}
render(){
return(
<>
<p>number:{this.state.number}</p>
<button onClick={()=>{
this.setState({
number: this.state.number + 1
})
}}>증가</button>
</>
)
}
}
export default ClassComponent;
실행을 해서 버튼을 누르면 숫자가 증가하면서 출력된다
react 에서는 props 나 state 값을 직접 변경하는 것이 허용되지 않는다
props 나 state 는 변경할 수 없는 데이터로 만들어 진 것(Virtual DOM)
변경하고자 하면 다른 곳에 복제를 해서 변경을 해야한다.
생성자가 아닌 메서드 외부애서 생성해도 인스턴스가 소유하기 때문에 성자에서 생성한 것 과 같은 효과를 가짐
ClassComponent.jsx
import React, { Component } from "react";
class ClassComponent extends Component{
//생성자
/*
constructor(props){
super(props);
this.state = {
number:0
}
}
*/
// 생성자가 아닌 메서드 외부애서 생성해도 인스턴스가 소유하기 때문에
// 생성자에서 생성한 것 과 같은 효과를 가짐
state = {
number:1
}
render(){
return(
<>
<p>number:{this.state.number}</p>
<button onClick={()=>{
this.setState({
number: this.state.number + 1
})
}}>증가</button>
</>
)
}
}
export default ClassComponent;
setState 에는 state 수정 구문을 삽입하는데 수정 구문 대신에 함수를 대입해도 가능
함수는 state 를 매개변수로 받고 state 의 수정 구문을 return 해주면 된다.
ClassComponent.jsx 파일의 button 생성 코드 수정
ClassComponent.jsx
import React, { Component } from "react";
class ClassComponent extends Component{
//생성자
/*
constructor(props){
super(props);
this.state = {
number:0
}
}
*/
// 생성자가 아닌 메서드 외부애서 생성해도 인스턴스가 소유하기 때문에
// 생성자에서 생성한 것 과 같은 효과를 가짐
state = {
number:1
}
render(){
return(
<>
<p>number:{this.state.number}</p>
<button onClick={()=>{
this.setState(
(prevState) => {return {number:prevState.number + 1}}
)
}}>증가</button>
</>
)
}
}
export default ClassComponent;
<동기 VS 비동기 >
동기 (Synchronous)
- 순차적으로 실행, 하나의 명령이 종료된 후 다른 명령을 수행
- 앞의 작업이 끝나야 다음 작업이 수행되는 구조라서 앞의 작업이 끝나고 난 후 작업을 수행하거나 결과를 사용하고자 하는 것이 어렵지 않음(결과를 리턴)
비동기 (ASynchronous)
- 하나의 명령이 수행 중인 동안에 다른 명령을 수행할 수 있는 방식 - 스레드
- 현재 작업이 끝나고 난 후 수행되는 코드를 만들 때는 콜백을 사용하거나 Promise 또는 async & await 구문을 활용
- 콜백을 사용할 때는 매개변수를 잘 파악해야 한다
- 매개변수가 작업의 결과인 경우가 많음
setState 로 state 를 변경하고 난 후 호출되는 콜백을 사용하고자 할 때는 setState 의 두번째 매개변수로 함수를 대입하면 된다.
ClssComponent 에서 state 의 변화가 생기고 난 후 호출되는 코드 작성
ClassComponent.jsx
import React, { Component } from "react";
class ClassComponent extends Component{
//생성자
/*
constructor(props){
super(props);
this.state = {
number:0
}
}
*/
// 생성자가 아닌 메서드 외부애서 생성해도 인스턴스가 소유하기 때문에
// 생성자에서 생성한 것 과 같은 효과를 가짐
state = {
number:1
}
render(){
return(
<>
<p>number:{this.state.number}</p>
<button onClick={()=>{
this.setState(
(prevState) => {return {number:prevState.number + 1}}, //상태 변하는 문장 뒤에 , 입력 후 함수 작성
() =>{console.log("상태 변화 발생!!!!");}
)
}}>증가</button>
</>
)
}
}
export default ClassComponent;
state 는 setState 메서드로만 수정해야 하고 객체 나 배열을 수정하고자 하는 경우는 복사본을 만들고 복사본을 수정한 후 그 복사본을 setState에 대입해서 업데이트 해야한다
배열이나 문자열의 경우 메서드가 원본에 작업을 수행하는지, 아니면 복사본에 수행한 후 리턴하는지 확인을 해볼 필요가 있다
import React, { Component } from "react";
class ClassComponent extends Component{
//생성자
/*
constructor(props){
super(props);
this.state = {
number:0
}
}
*/
// 생성자가 아닌 메서드 외부애서 생성해도 인스턴스가 소유하기 때문에
// 생성자에서 생성한 것 과 같은 효과를 가짐
state = {
number:1
}
render(){
return(
<>
<p>number:{this.state.number}</p>
<button onClick={()=>{
this.setState(
(prevState) => {return {number:prevState.number + 1}}, //상태 변하는 문장 뒤에 , 입력 후 함수 작성
() =>{
console.log("상태 변화 발생!!!!");
let ar = ["a","b","c"];
//원본을 변경하는 메서드
ar.push("d");
console.log(ar);
}
)
}}>증가</button>
</>
)
}
}
export default ClassComponent;
import React, { Component } from "react";
class ClassComponent extends Component{
//생성자
/*
constructor(props){
super(props);
this.state = {
number:0
}
}
*/
// 생성자가 아닌 메서드 외부애서 생성해도 인스턴스가 소유하기 때문에
// 생성자에서 생성한 것 과 같은 효과를 가짐
state = {
number:1
}
render(){
return(
<>
<p>number:{this.state.number}</p>
<button onClick={()=>{
this.setState(
(prevState) => {return {number:prevState.number + 1}}, //상태 변하는 문장 뒤에 , 입력 후 함수 작성
() =>{
console.log("상태 변화 발생!!!!");
let ar = ["a","b","c"];
//원본을 변경하는 메서드
ar.push("d");
console.log(ar);
// 요소를 순회하면서 함수를 수행해서 그 결과를
// 가지고 새로운 배열을 만들어서 리턴하는 함수
console.log(ar.map((e)=>{return e + "알파벳"}));
}
)
}}>증가</button>
</>
)
}
}
export default ClassComponent;
<div class = 'outer'>
<div class = 'inner'>
</div>
</div>
outer와 inner 모두에 click에 대한 이벤트 처리 핸들러가 존재하는 경우 inner에서 click이 발생하면 inner의 click에 해당하는 event handler를 수행 한 후 outer의 click에 해당하는 event handler를 수행하는 것이 event bubbling
event bubbling 을 막고자 할 때는 Event 객체가 stopPropagation()을 호출하면 된다.
Input 에 입력된 값은 value 속성에 저장
이벤트 처리를 수행할 Component를 생성 - EventComponent.jsx
EventComponent.jsx
import React, {Component} from "react";
class EventComponent extends Component{
render(){
return(
<>
<h1>이벤트 연습</h1>
<input type="text" placeholder="이름을 입력해주세요"/>
</>
)
}
}
export default EventComponent;
App.js
import MyComponent from './MyComponent';
import ClassComponent from './ClassComponent';
import EventComponent from './EventComponent';
function App() {
return (
<>
<EventComponent/>
<ClassComponent/>
<MyComponent name="아담" favoriteNumber={3} children="my son"/>
</>
)
}
export default App;
EventComponent.jsx
import React, {Component} from "react";
class EventComponent extends Component{
render(){
return(
<>
<h1>이벤트 연습</h1>
<input type="text" placeholder="이름을 입력해주세요"
onChange={(e)=>{
//입력하는 내용을 콘솔에 출력
console.log(e.target.value);
}}/>
</>
)
}
}
export default EventComponent;
EventComponent.jsx
import React, {Component} from "react";
class EventComponent extends Component{
constructor(props){
super(props);
this.state = {
name:''
}
}
render(){
return(
<>
<h1>이벤트 연습</h1>
<input type="text" placeholder="이름을 입력해주세요"
value={this.state.name}
onChange={(e)=>{
//입력하는 내용을 콘솔에 출력
//console.log(e.target.value);
//입력된 값을 name 에 저장
this.setState({
name:e.target.value
})
}}/>
</>
)
}
}
export default EventComponent;
EventComponent.jsx
import React, {Component} from "react";
class EventComponent extends Component{
constructor(props){
super(props);
this.state = {
name:''
}
}
render(){
return(
<>
<h1>이벤트 연습</h1>
<input type="text" placeholder="이름을 입력해주세요"
value={this.state.name}
onChange={(e)=>{
//입력하는 내용을 콘솔에 출력
//console.log(e.target.value);
//입력된 값을 name 에 저장
this.setState({
name:e.target.value
})
}}/>
<button onClick={(e)=>{
alert(this.state.name);
this.setState({
name:''
})
}}>버튼</button>
<input type='button' value = '버튼'/>
</>
)
}
}
export default EventComponent;
이벤트 처리의 내용이 많으면 DOM 생성 태그 안에 많은 양의 자바스크립트 코드를 작성하면 가독성이 떨어지게 되고, 공유 데이터를 핸들링하는 경우에 대부분의 경우 공유 데이터는 App.js 에 존재할 가능성이 높은데,
이 경우 App.js 에 함수를 만들어 처리하는 것이 수월하므로 App.js나 상위 컴포넌트에서 이벤트 처리 함수를 만들어서 하위 컴포넌트에게 전달하는데 이 경우는 함수를 연결하는 형태로 이벤트를 처리하게 된다.
동일한 내용을 별도의 함수로 만들어서 처리
클래스 내의 함수에서 this 를 사용하고자 하는 경우 화살표 함수를 만들면 안됨
let f = function(){
내용
this.
}
// 화살표 함수에서는 this 와 arguments를 사용할 수 없다
let f = () =>{
내용
this.
}
EventComponent.jsx
import React, {Component} from "react";
class EventComponent extends Component{
//input 의 내용이 변경될 때 호출될 함수
handleChange(e){
this.setState({
name:e.target.value
})
}
//버튼을 클릭했을 때 호출 될 함수
handleClick(e){
alert(this.state.name);
this.setState({
name:''
})
}
constructor(props){
super(props);
this.state = {
name:''
}
// 같은 클래스에 속했다고 해서 아래에서 불러올 수 없다
// 클래스의 구조일분 인스턴스의 구조는 아니기 때문
this.handleClick = this.handleClick.bind(this);
this.handleChange = this.handleChange.bind(this);// 이 구문 매우 중요
}
render(){
return(
<>
<h1>이벤트 연습</h1>
<input type="text" placeholder="이름을 입력해주세요"
value={this.state.name}
onChange={this.handleChange}/>
<button onClick={this.handleClick}>버튼</button>
<input type='button' value = '버튼'/>
</>
)
}
}
export default EventComponent;
리액트는 바벨이 크로스 컴파일링 (ECMA 2015+ 이상의 문법으로 작성된 스크립트 코드를 하위 버전에 호환될 수 있게 변환)을 수행해주는데 클래스 안에 만든 요소를 클래스 안에서 this를 이용해서 접근할 수 있도록 지원
앞의 컴포넌트를 수정 - 이제 바인딩 작업이 필요없다
생성자에서 변환하는 작업을 안할 수 있음
EventComponent.jsx
import React, {Component} from "react";
class EventComponent extends Component{
//input 의 내용이 변경될 때 호출될 함수
state = {
name: ''
}
handleChange = (e) => {
this.setState({
name:e.target.value
})
}
//버튼을 클릭했을 때 호출 될 함수
handleClick = (e) => {
alert(this.state.name);
this.setState({
name:''
})
}
constructor(props){
super(props);
this.state = {
name:''
}
}
render(){
return(
<>
<h1>이벤트 연습</h1>
<input type="text" placeholder="이름을 입력해주세요"
value={this.state.name}
onChange={this.handleChange}/>
<button onClick={this.handleClick}>버튼</button>
<input type='button' value = '버튼'/>
</>
)
}
}
export default EventComponent;
하나의 여러 가지 이벤트 또는 여러 객체의 동일한 이벤트를 하나의 객체 또는 함수를 가지고 처리하는 것
유사한 이벤트 처리를 위해서 함수를 여러 개 만들거나 객체를 여러 개 만드는 것도 자원의 낭비
Event Routing 을 하게 되면 이벤트가 발생한 객체를 구분할 수 있어야 하는데 자바스크립트 에서는 DOM객체를 찾아서 비교하지만, 리액트에서는 name 속성에 값을 부여한 후 e.target.name 속성을 가지고 구분한다 HTML 의 DOM 만 사용하는 것이 아니므로 id속성을 이용해서 DOM 을 찾는 것을 권장하지 않음
리액트를 하다 보면 아래와 같은 코드는 보이지 않음
이전 컴포넌트를 수정 - input을 2개로 늘릴 것임
EventComponent.jsx
import React, {Component} from "react";
class EventComponent extends Component{
//input 의 내용이 변경될 때 호출될 함수
state = {
name: '',
age: ''
}
handleNameChange = (e) =>{
this.setState({
name:e.target.value
})
}
handleAgeChange = (e) =>{
this.setState({
age:e.target.value
})
}
render(){
return(
<>
<h1>이벤트 연습</h1>
<input type='text' value = {this.state.name} //전달 - value
placeholder='이름 입력' onChange={this.handleNameChange}/>
<input type='text' value={this.state.age}
placeholder='나이 입력' onChange={this.handleAgeChange}/>
<button>확인</button>
</>
)
}
}
export default EventComponent;
EventComponent.jsx
import React, {Component} from "react";
class EventComponent extends Component{
//input 의 내용이 변경될 때 호출될 함수
state = {
name: '',
age: ''
}
handleNameChange = (e) =>{
this.setState({
name:e.target.value
})
}
handleAgeChange = (e) =>{
this.setState({
age:e.target.value
})
}
handleClick = (e) => {
alert(this.state.name + ':' + this.state.age);
this.setState({
name : '',
age : ''
})
}
render(){
return(
<>
<h1>이벤트 연습</h1>
<input type='text' value = {this.state.name} //전달 - value
placeholder='이름 입력' onChange={this.handleNameChange}/>
<input type='text' value={this.state.age}
placeholder='나이 입력' onChange={this.handleAgeChange}/>
<button onClick={this.handleClick}>확인</button>
</>
)
}
}
export default EventComponent;
EventComponent.jsx
import React, {Component} from "react";
class EventComponent extends Component{
//input 의 내용이 변경될 때 호출될 함수
state = {
name: '',
age: ''
}
handleChange = (e) =>{
// 이벤트가 발생한 객체의 이름과 동일한 state 의 값을
// 입력한 내용으로 수정
this.setState({
[e.target.name]:e.target.value
})
}
handleClick = (e) => {
alert(this.state.name + ':' + this.state.age);
this.setState({
name : '',
age : ''
})
}
render(){
return(
<>
<h1>이벤트 연습</h1>
<input type='text' value = {this.state.name} name = 'name' //전달 - value
placeholder='이름 입력' onChange={this.handleChange}/>
<input type='text' value={this.state.age} name = 'age'
placeholder='나이 입력' onChange={this.handleChange}/>
<button onClick={this.handleClick}>확인</button>
</>
)
}
}
export default EventComponent;
EventComponent.jsx
import React, {Component} from "react";
class EventComponent extends Component{
//input 의 내용이 변경될 때 호출될 함수
state = {
name: '',
age: ''
}
handleChange = (e) =>{
// 이벤트가 발생한 객체의 이름과 동일한 state 의 값을
// 입력한 내용으로 수정
this.setState({
[e.target.name]:e.target.value
})
}
handleClick = (e) => {
alert(this.state.name + ':' + this.state.age);
this.setState({
name : '',
age : ''
})
}
// input의 KeyPress 이벤트 연결할 함수
handleKeyPress = (e) => {
//alert(e.key) //그냥 확인하는 방법
//누른 키가 Enter 라면 handleClick 함수를 호출
//이벤트를 강제로 발생시키는 것을 Event - Trigger 라고 한다
if(e.key === 'Enter'){
this.handleClick();
}
}
render(){
return(
<>
<h1>이벤트 연습</h1>
<input type='text' value = {this.state.name} name = 'name' //전달 - value
placeholder='이름 입력' onChange={this.handleChange}/>
<input type='text' value={this.state.age} name = 'age'
placeholder='나이 입력' onChange={this.handleChange} //나이 입력에 onKeyPress 적용
onKeyPress={this.handleKeyPress}/>
<button onClick={this.handleClick}>확인</button>
</>
)
}
}
export default EventComponent;
input 의 defaultValue 나 defaultChecked 속성을 이용하면 기본값이나 기본 체크를 설정할 수 있다.
file 은 보안 문제 때문에 value 값을 가져오는 것은 가능하지만 value를 설정하는 것은 안된다.
checkbox의 체크 여부를 가져오고자 하는 경우에는 e.target.checked 로 가져오면 된다.
file
이벤트가 발생했을 때 이 이벤트와 관련된 웹 브라우저의 기본 구현 내용을 실행하지 않도록 해주는 함수
form 의 submit 이벤트는 form의 데이터를 action으로 설정한 곳으로 전송하는 기능을 내장하고 있고 form 의 reset 이벤트는 form의 데이터를 삭제하는 기능을 내장하고 있으며 브라우저는 DragAndDrop 이벤트 발생 시 drop 을 막아버리는 기능을 내장하고 있음
웹에서 입력할 수 있는 도구
- input : text, passwd, checkbox, radio,
file, hidden(보이지는 않는 속성이지만 서버에게 데이터를 전달하고자 하는 경우 사용)
, image, button, submit, reset
<checkbox 와 radio 는 하나의 그룹이 되려면 name의 값이 같아야 하고,
value를 설정해주는 것이 좋다
value 설정이 안되어 있으면 on 이나 off 가 서버에게 전송되고
value 가 설정되어 있으면 value가 넘어간다>
- textarea : 여러 줄의 문자열, 태그 와 태그 사이에 내용이 들어가기 때문에
설정을 할 때에는 value 가 아니고 innerHTML 이고 입력된 내용을 가져올 때는 value
여는 태그 와 닫는 태그의 라인이 다르면 첫 커서가 중간에 들어간다
- select : 목록 중에 하나를 선택
select 에 name 을 설정하고 option 으로 항목을 만드는데
value를 설정해줘야 함
EventComponent.jsx
import React, {Component} from "react";
class EventComponent extends Component{
state={
name:'',
content:'',
image: []
}
handleChange = (e) => {
this.setState({
[e.target.name]:e.target.value
})
}
handleClick = (e) => {
alert(this.state.name + '+' + this.state.content);
console.log(this.state.image);
}
render(){
return(
<>
<h1>이벤트 연습</h1>
<input type='text' name = 'name' defaultValue='No Name'
onChange={this.handleChange} />
<br />
<fieldset>
<legend>성별</legend>
<input type='radio' name = 'gender' value='man'defaultChecked/>남자
<input type='radio' name = 'gender' value='woman'/>여자
</fieldset>
<textarea name='content' onChange = {this.handleChange}></textarea>
<select name='cnt'>
<option value = '1'>1</option>
<option value = '2'>2</option>
<option value = '3'>3</option>
</select>
<input type='file' name='image' multiple='multiple'
accept='iamge/*' onChange={this.handleChange}/>
<br/>
<button onClick={this.handleClick}>전송</button>
</>
)
}
}
export default EventComponent;
EventComponent.jsx
import React, {Component} from "react";
class EventComponent extends Component{
state={
image: []
}
//파일의 경우는 files 속성을 state 에 연결해야 한다
//file 의 경우는 e.target.value 를 호출하면 파일의 절대경로를 문자열로 리턴
//이 데이터는 서버로 전송하면 문자열이 된다.
handleChange = (e) => {
this.setState({
[e.target.name]:e.target.files
})
}
handleClick = (e) => {
console.log(this.state.image);
}
render(){
return(
<>
<h1>이벤트 연습</h1>
<input type='file' name='image' multiple='multiple'
accept='iamge/*' onChange={this.handleChange}/>
<br/>
<button onClick={this.handleClick}>전송</button>
</>
)
}
}
export default EventComponent;
브라우저는 Drag 이벤트가 발생할 때 Drop 이벤트를 중지시키는 기보 기능을 내장하고 있음
Drop 이벤트를 사용하고자 할 때는 첫 번째 문장이 e.preventDefault()가 되어야 한다.