React +2 (All of Components)

LEE EUI JOO·2023년 2월 7일
0

Web Programming

목록 보기
11/17
post-custom-banner


Component

개념

  • MVC(Model View Controller) : 기능 별로 나누어서 구현

    • Model : 데이터베이스에 작업을 수행하는 Persistance 계층 과 Bussiness Logic을 수행하는 Service 계층을 합친 것

    • View : 화면 출력 부분

    • Controller : Model 과 View 사이를 연결

  • MVC 구조의 View를 독립적으로 구성한 개체

  • Component를 여러 개 조합해서 하나의 화면을 생성

  • 데이터의 변경이나 이벤트가 발생하면 화면을 리랜더링 하지 않고 Component를 리랜더링 하는 개념

  • 여러가지 기능을 소유하고 있기 때문에 단순한 View 와는 다르다

  • 서버 사이드 템플릿 엔진은 데이터를 출력하는 용도 외에는 사용할 수 없는데 Component 는 여러 가지 기능을 내장한다


종류

  • 함수형 컴포넌트 : 함수를 가지고 생성

  • 클래스형 컴포넌트 : 클래스를 가지고 생성

  • ❓ 함수가 클래스의 인스턴스 보다는 가볍고, 클래스가 함수보다는 안전하다

  • 최근에는 속도 때문에 함수형 컴포넌트를 권장함 - Life Cycle(수명주기) 를 이용하는 경우가 아니라면 함수형 컴포넌트를 사용


클래스형 컴포넌트 생성 및 사용

  • 생성
    • 컴포넌트 클래스를 상속해서 생성
    • render 함수를 구현해서 출력할 JSX를 리턴
  • 파일의 확장자는 js 나 jsx를 사용(TypeScript 를 사용하는 경우는 ts 나 tsx로 작성)
  • src 디렉토리에 jsx 파일을 생성하고 작성

기본 틀 - MyComponent.jsx


import React, {Component} from "react";

class MyComponent extends Component{
    render(){
        return(
            <div>
                컴포넌트 첫번째
            </div>

        )
    }

}

export default MyComponent
  • 대부분의 경우 index.js를 수정하지 않고 App.js 파일을 수정해서 MyComponent를 사용 - app.js 수정

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


props - properties 의 약자로 태그의 속정

  • 컴포넌트를 만들 때 이름 = 값의 형태로 설정

  • 클래스 형 컴포넌트에서는 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;
  • MyComponent.jsx 파일 수정
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

  • props 의 값을 변경하고자 하면 다른 변수를 생성해서 수행해야 한다

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

  • props 를 쓰고자 한다면 매개변수에 props

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;

  • 함수형 컨포넌트에서 props 기본값 설정

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


태그 안의 내용 활용

  • 태그 안의 내용은 props.children으로 접근이 가능

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

유효성 검사

  • 필수 나 자료형을 설정해두는 것이 가능
  • prop-types 를 import 해서 설정
    • 컴포넌트이름.propTypes = {속성이름 : prop-types.자료형}
  • props 의 값이 문자열이 아닌 경우는 {} 안에 작성해야 한다

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;

자료형 Check

  • array : 배열

  • bool : boolean

  • func : 함수 - 자바스크립트에서는 함수도 하나의 자료형

  • number : 숫자

  • object : 객체

  • string : 문자열

  • node : 화면에 출력될 수 있는 모든 것

  • element : react 요소

  • any : 모든 자료형

  • instanceOf(클래스 이름) : 클래스로부터 파생된 인스턴스
  • OneOf([데이터 나열]) : 나열된 데이터 중 하나 - 데이터를 나열하기 때문에 enum에 가까움
  • oneOfType([자료형 나열]) : 나열된 자료형 중 하나

클래스형 component 에서 props 사용

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;


Component 의 Props - react 공식 문서

  • All React Component must act like pure functions with respect to their props

  • 모든 react component는 그들의 props에 관해서는 Pure 함수 같은 역할

  • pure function(순수 함수)
    • 입력으로 받은 매개변수의 데이터를 수정하지 않는다
    • 외부의 데이터에 영향을 주지 않는 함수
  • 동일한 입력이 주어지면 동일한 결과를 리턴해야 한다

state

  • props 는 상위 컴포넌트가 하위 컴포넌트에게 넘겨주는 데이터 - 데이터를 상위 컴포넌트에서 만들기 때문에 하위 컴포넌트에서 변경하지 못하도록 함

  • state 는 컴포넌트 내부에서 만드는 데이터로 읽기와 수정 모두 가능

  • 초기화

    • class 형 컴포넌트의 경우는 생성자나 render 메서드 외부에서 수행
    • this.state = {상태이름:값, 상태이름:값...} 형태로 초기화
  • get

    • this.state.상태이름
  • set

    • setState({상태이름:값, 상태이름:값...}) 을 이용해서 변경

화면에 출력될 Component 를 생성 - ClassComponent.jsx

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 값이 변경이 되면 Component 가 다시 출력된다
  • 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;

CallBack : 이벤트가 발생하거나 상태 변화가 수행된 후 호출되는 함수

  • 대부분 비동기가 처리
<동기 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;


Event Handling

용어

  • Event : 사용자 또는 시스템이 발생시키는 사건
  • Event Handler, Event Listener : 이벤트가 발생했을 때 호출되는 함수 또는 함수를 소유한 객체

자바스크립트 에서의 이벤트 처리

  • DOM 객체.addEventListener('이벤트 이름',(e) => { 이벤트가 발생했을 때 수행할 내용 }

이벤트 처리 함수에 전달되는 객체 - Event 타입

  • type : 이벤트 이름으로 대소문자를 구분하지 않음
  • isTrusted : 웹 브라우저에서 발생한 이벤트(true)인지 프로그래밍으로 발생한 것(false) 인지를 판단
  • target : 이벤트가 처음 발생한 객체
  • currentTarget : 이벤트 버블링이 발생한 경우 이벤트가 현재 위치한 객체
  • bubbles : 버블링 여부

리액트의 이벤트 종류 - https://reactjs.org/docs/events.html

  • 이벤트 속성은 on 으로 시작하고 camel case
  • 이벤트 속성에 연결하는 것은 자바스크립트 코드가 아니고 함수 형태의 값을 전달
  • Component에는 이벤트를 설정할 수 없고 DOM에만 이벤트를 연결
    • Component 에서 on이름 = 데이터를 넘기는 것은 이벤트 핸들링이 아니고 property를 넘기는 것

Event Bubbling

  • 하위 요소에서 발생한 이벤트가 상위 요소에게 전파 되는 것
  • 자바스크립트의 DOM은 기본적으로 Event Bubbling을 수행
<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 의 onChange : input의 내용이 변경되었을 때 발생하는 이벤트

  • 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;
  • 입력 내용을 콘솔에 출력하는 이벤트 설정

  • 입력한 내용을 state에 저장

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;
  • 콘솔에 출력되지 않음

현재화면에 button 을 추가해서 버튼의 클릭 이벤트 처리 - name의 내용을 대화상자로 출력하고 name 을 초기화

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;

  • 초기화

  • Component 내에 이벤트 처리 코드를 작성할 때는 이런 방식으로 많이 수행한다!!

별도의 함수로 이벤트 처리

  • 이벤트 처리의 내용이 많으면 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;


바벨의 transform-class-properties 문법

  • 리액트는 바벨이 크로스 컴파일링 (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

  • 하나의 여러 가지 이벤트 또는 여러 객체의 동일한 이벤트를 하나의 객체 또는 함수를 가지고 처리하는 것

  • 유사한 이벤트 처리를 위해서 함수를 여러 개 만들거나 객체를 여러 개 만드는 것도 자원의 낭비

  • Event Routing 을 하게 되면 이벤트가 발생한 객체를 구분할 수 있어야 하는데 자바스크립트 에서는 DOM객체를 찾아서 비교하지만, 리액트에서는 name 속성에 값을 부여한 후 e.target.name 속성을 가지고 구분한다 HTML 의 DOM 만 사용하는 것이 아니므로 id속성을 이용해서 DOM 을 찾는 것을 권장하지 않음

  • 리액트를 하다 보면 아래와 같은 코드는 보이지 않음

    • document.getElementByid("아이디")
    • document.querySelector("선택자")
  • 이전 컴포넌트를 수정 - 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;

  • alert 추가

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;

  • 코드를 수정해서 2개의 input 의 change 이벤트를 하나의 함수로 처리

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;
  • 동일한 결과

onKeyPress - 트리거(Trigger) 사용

  • 키보드를 눌렀을 때 발생하는 이벤트 객체의 key 속성을 확인하면 누른 keyboard의 값을 확인할 수 있음

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;
  • Enter 누르면 입력


Input 태그의 기타 속성

  • input 의 defaultValue 나 defaultChecked 속성을 이용하면 기본값이나 기본 체크를 설정할 수 있다.

  • file 은 보안 문제 때문에 value 값을 가져오는 것은 가능하지만 value를 설정하는 것은 안된다.

  • checkbox의 체크 여부를 가져오고자 하는 경우에는 e.target.checked 로 가져오면 된다.

  • file

    • multiple 속성의 값이 false 이면 하나만 선택이 가능하고 true 이면 여러 개 선택이 가능.
    • accept 속성을 이용하면 파일의 종류를 제한하는 것이 가능 - images/* 로 설정하면 그림파일만 선택이 가능하고 text/plain 으로 설정하면 텍스트 파일로 제한
    • 선택한 파일의 목록은 e.target.files 로 가져올 수 있는데, 이 속성은 자바스크립트의 FileList

Event 객체의 preventDefault()

  • 이벤트가 발생했을 때 이 이벤트와 관련된 웹 브라우저의 기본 구현 내용을 실행하지 않도록 해주는 함수

  • 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를 설정해줘야 함
  • 클라이언트 사이드 렌더링을 할 때는 submit 이벤트를 사용하지 않고 ajax, fetch api, axios 라이브러리 등을 이용해서 서버에 데이터를 전송하기 때문에 입력한 내용을 가져와, get 방식의 파라미터를 만드는 것, 그리고 json 형식의 파라미터를 만드는 것 과 file이 존재하는 파라미터를 만드는 것이 중요하다

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;

  • 전송 button 클릭


Drag & Drop 이벤트 사용 시 주의사항

  • 브라우저는 Drag 이벤트가 발생할 때 Drop 이벤트를 중지시키는 기보 기능을 내장하고 있음

  • Drop 이벤트를 사용하고자 할 때는 첫 번째 문장이 e.preventDefault()가 되어야 한다.


profile
무럭무럭 자라볼까
post-custom-banner

0개의 댓글