하고 싶은게 많음

[혼공자스] 10. 리액트 라이브러리 맛보기 본문

IT/자바스크립트

[혼공자스] 10. 리액트 라이브러리 맛보기

쏘매띵 2022. 12. 6. 09:07

 

 

 

 

리액트 라이브러리 : 규모가 큰 자바스크립트 라이브러리. 사용자 인터페이스를 쉽게 구성할 수 있도록 도와줌.

 

리액트 라이브러리 사용 준비하기

 

https://unpkg.com/react@17/umd/react.development.js
https://unpkg.com/react-dom@17/umd/react-dom.development.js
https://unpkg.com/babel-standalone@6/babel.min.js
<!DOCTYPE html>
<html>
<head>
   <title>Document</title>
   <!--리액트 사용 준비-->
   <script src = "https://unpkg.com/react@17/umd/react.development.js"></script>
   <script src = "https://unpkg.com/react-dom@17/umd/react-dom.development.js"></script>
   <script src = "https://unpkg.com/babel-standalone@6/babel.min.js"></script>
</head>
<body>
   <div id ="root"></div>
   <!--리액트를 사용하는 코드 입력-->
   <script type ="text/babel"></script>
</body>
</html>

리액트 라이브러리는 단순한 자바스크립트가 아니라 리액트를 위해서 개발된 자바스크립트 확장 문법을 사용. 이러한 문

법을 사용하려면 바벨babel이라는 라이브러리를 추가로 읽어들이고 바벨을 적용할 부분을 지정해야한다. 

바벨 라이브러리를 추가로 읽어들이고 바벨을 적용할 부분을 지정하는 선언부

 

 

 

루트 컴포넌트 출력하기

컴포넌트 component  " 리액트에서 화면에 출력되는 요소 "

루프 컴포넌트 root component " 컴포넌트 중 가장 최상위에 배치하는 컴포넌트 "

리액트는 컴포넌트를 만들 떼 HTML요소를 만드는 것과 동일한 문법을 사용.

컴포넌트 생성하기
<컴포넌트 이름></컴포넌트 f이름>

 

 

생성한 컴포넌트를 출력할 때는 ReactDOM.render( ) 메소드 사용. 

컨테이너 container  " 컴포넌트를 출력할 상자 "

컨포넌트 출력하기
ReactDOM.render(컴포넌트, 컨테이너)

 

//루트 컴포넌트 출력하기
<!DOCTYPE html>
<html>
<head>
   <title>Document</title>
   <!--리액트 사용 준비-->
   <script src = "https://unpkg.com/react@17/umd/react.development.js"></script>
   <script src = "https://unpkg.com/react-dom@17/umd/react-dom.development.js"></script>
   <script src = "https://unpkg.com/babel-standalone@6/babel.min.js"></script>
</head>
<body>
   <div id ="root"></div>
   <script type ="text/babel">
      //컴포넌트와 컨테이너 생성하기
      const component = <h1>리액트 기본</h1>
      const container = document.getElementById('root')

      //출력
      ReactDOM.render(component, container)
   </script>
</body>
</html>

    ㄴh1컴포넌트를 생성하고, h1컴포넌트를 출력할 div#root를 읽어들인 뒤, ReactDOM.render( ) 메소드로 컴포넌트를 div#root에 출력. 만약 div#root를 선언하지 않았다면 화면에는 아무 것도 뜨지않았을거임.

 

 

자바 스크립트 코드 내부에 HTML 코드를 사용한 모습을 볼 수 있는데 이러한 문법은 JSX(자바스크칩트 확장 문법)이라고함. 웹 브라우저는 사실 이러한  코드를 읽고 실행하지 못한다. 바벨이 JSX 코드를 읽고  일반적인 자바스크립트 문법으로 변환한 뒤 실행해주므로 이러한 코드가 사용 가능한 것.

바벨 공식 홈페이지에서 바벨 REPL도구를 사용하면 바벨이 어떤 식으로 코드를 바꾸는지 확인 가능

 

 

https://babeljs.io/repl

 

 

Babel · The compiler for next generation JavaScript

The compiler for next generation JavaScript

babeljs.io

 

 

 

 

JSX(JavaScripteXtension) 기본 문법

 

표현식 출력하기
<태그>{표현식}</태그>
<태그 속성 = {표현식} />

※ 다만, 속성으로 표현식을 출력할 때는 따옴표를 사용하면 안됨.

 

//표현식 출력하기
<!DOCTYPE html>
<html>
<head>
   <title>Document</title>
   <!--리액트 사용 준비-->
   <script src = "https://unpkg.com/react@17/umd/react.development.js"></script>
   <script src = "https://unpkg.com/react-dom@17/umd/react-dom.development.js"></script>
   <script src = "https://unpkg.com/babel-standalone@6/babel.min.js"></script>
</head>
<body>
   <div id ="root"></div>
   <script type ="text/babel">
      //상수 선언
      const name = '구름'
      const imgUrl = 'http://placedog.net/400/200'

      //컴포넌트와 컨테이너 생성
      const component = <div>
         <h1>{name} 님 안녕하세요! </h1>
         <img src = {imgUrl} />
      </div>
      const container = document.getElementById('root')

      //출력
      ReactDOM.render(component, container)
   </script>
</body>
</html>

 


 

클래스 컴포넌트

 

React사용 시
this.state: 화면에 출력할 건 this.state로 지정
setState: 변경할 때 사용
ComponentDidMount : 추가될 때 사용
ComponentWillUnmount : 화면에서 제거할 때 사용

 

HTML 표준에 포함된 태그로 컴포넌트를 만들 수 있지만, 사용자가 직접 클래스 또는 함수를 이용해 컴포넌트를 만들 수 있음.

클래스 컴포넌트: 클래스로 만드는 컴포넌트

함수 컴포넌트: 함수로 만드는 컴포넌트

클래스 컴포넌트 만들기
class 컴포넌트 이름 extends React.Component {
   render ( ) {
       return <h1> 출력할 것 </h1>
   }
}

React.Component 클래스의 상속을 받아야 컴포넌트로 동작할 수 있게 하는 속성과 메소드를 받을 수 있음. React.Component 클래스는 화면에 무언가를 출력할 때 render( ) 메소드를 호출함. 이를 오버라이드해서 원하는 것을 출력함.

 

//루프 컴포넌트 출력을 클래스 컴포넌트로 구현하기
<!DOCTYPE html>
<html>
<head>
   <title>Document</title>
   <!--리액트 사용 준비-->
   <script src = "https://unpkg.com/react@17/umd/react.development.js"></script>
   <script src = "https://unpkg.com/react-dom@17/umd/react-dom.development.js"></script>
   <script src = "https://unpkg.com/babel-standalone@6/babel.min.js"></script>
</head>
<body>
   <div id ="root"></div>
   <script type ="text/babel">
      //애플리케이션 클래스 생성
      class App extends React.Component {
         render () {
            return <h1>리액트 기본</h1>
         }
      }

      //출력
      const container = document.getElementById('root')
      ReactDOM.render(<App />, container)
   </script>
</body>
</html>

 

 

클래스 컴포넌트를 사용하면 클래스 메소드 내부에서 this.props 속성을 사용할 수 있었음. 이 속성은 컴포넌트를 선언할 때 전달함.

//컴포넌트의 속성 사용하기
<!DOCTYPE html>
<html>
<head>
   <title>Document</title>
   <!--리액트 사용 준비-->
   <script src = "https://unpkg.com/react@17/umd/react.development.js"></script>
   <script src = "https://unpkg.com/react-dom@17/umd/react-dom.development.js"></script>
   <script src = "https://unpkg.com/babel-standalone@6/babel.min.js"></script>
</head>
<body>
   <div id ="root"></div>
   <script type ="text/babel">
      //애플리케이션 클래스 생성
      class App extends React.Component {
         render () {
            return <div>
               <h1>{this.props.name} 님 안녕하세요!</h1>
               <img src = {this.props.imgUrl} />
            </div>
         }
      }

      //출력하기
      const container = document.getElementById('root')
      ReactDOM.render(<App name = "쏘매띵" imgUrl = "http://placedog.net/400/200" />,
      container)
   </script>
</body>
</html>

 

컴포넌트의 기본적인 속성과 메소드 436

클래스의 메소드 오버라이드 하기
class App extends React.Component {     
   constructor (props) {
        super(props)
        //생성자 코드
    }     
    render() {
        //출력할 것
     }     
     componentDidMount () {
        //컴포넌트가 화면에 출력될 때 호출
      }       
     componentWillUnmount() {
        //컴포넌트가 화면에서 제거될 때 호출
      }
}

 

우리가 변경해서 사용하는 속성으로는 state속성이 있음. state속성에는 출력할 값을 저장을 하는데 속성 값을 변경할 때는 반드시 setState( ) 메소드를 사용해야함.
setState( ) 메소드로 속성의 값을 변경하면 컴포넌트는 render( )메소드를 호출해서 화면에 변경 사항을 출력함.

 

//상태 선언하기 (생성자 위치)
this.state = { 속성 : 값 }
//상태 변경하기(이외의 위치)
this.setState ( { 변경할 속성 : 값 } )

 

//이벤트 연결하기
<!DOCTYPE html>
<html>
<head>
  <title>Document</title>
     <!--리액트 사용 준비-->
     <script src = "https://unpkg.com/react@17/umd/react.development.js"></script>
     <script src = "https://unpkg.com/react-dom@17/umd/react-dom.development.js"></script>
     <script src = "https://unpkg.com/babel-standalone@6/babel.min.js"></script>
</head>
<body>
  <div id ="root"></div>
  <script type ="text/babel">
    //애플리케이션 클래스 생성
    class App extends React.Component {
      constructor (props) {
        super(props)
        this.state = {
          count : 0
        }

        this.countUp = this.countUp.bind(this)
      }

      render() {
        return <div>
          <h1>클릭한 횟수: {this.state.count}</h1>
          <button onClick = {this.countUp}>클릭</button>
          </div>
      }

      countUp (event) {
        this.setState({
          count: this.state.count + 1
        })
      }
    }
    //출력하기
    const container = document.getElementById('root')
    ReactDOM.render(<App />, container)
  </script>
</body>
</html>

※ 대문자 소문자 잘 보고 작성해야한다! 안그럼 오류남! 리액트에서  JSX문법으로 이벤트를 연결할 때는 대소문자를 확실히 지켜서 입력해줘야함

 

 

 

onClick의 이름을 잘못 적었을 경우 이와 같은 경고문이 뜨는데 겁나 친절쓰

 

리액트 이벤트 이름을 확인할 수 있는 주소

https://ko.reactjs.org/docs/events.html#clipboard-events

 

합성 이벤트(SyntheticEvent) – React

A JavaScript library for building user interfaces

ko.reactjs.org

 

//이벤트 연결하기: 다른 this 바인드 방법(1)
<!DOCTYPE html>
<html>
<head>
  <title>Document</title>
     <!--리액트 사용 준비-->
     <script src = "https://unpkg.com/react@17/umd/react.development.js"></script>
     <script src = "https://unpkg.com/react-dom@17/umd/react-dom.development.js"></script>
     <script src = "https://unpkg.com/babel-standalone@6/babel.min.js"></script>
</head>
<body>
  <div id ="root"></div>
  <script type ="text/babel">
    //애플리케이션 클래스 생성
    class App extends React.Component {
      constructor (props) {
        super(props)
        this.state = {
          count : 0
        }
      }

      render() {
        return <div>
          <h1>클릭한 횟수: {this.state.count}</h1>
          <button onClick = {(e) => this.countUp(e)}>클릭</button>
          </div>
      }

      countUp (event) {
        this.setState({
          count: this.state.count + 1
        })
      }
    }
    //출력하기
    const container = document.getElementById('root')
    ReactDOM.render(<App />, container)
  </script>
</body>
</html>

결과는 위와 같음

 

//이벤트 연결하기: 다른 this 바인드 방법(2)
<!DOCTYPE html>
<html>
<head>
  <title>Document</title>
     <!--리액트 사용 준비-->
     <script src = "https://unpkg.com/react@17/umd/react.development.js"></script>
     <script src = "https://unpkg.com/react-dom@17/umd/react-dom.development.js"></script>
     <script src = "https://unpkg.com/babel-standalone@6/babel.min.js"></script>
</head>
<body>
  <div id ="root"></div>
  <script type ="text/babel">
    //애플리케이션 클래스 생성
    class App extends React.Component {
      constructor (props) {
        super(props)
        this.state = {
          count : 0
        }
      }

      render() {
        return <div>
          <h1>클릭한 횟수: {this.state.count}</h1>
          <button onClick = {this.countUp}>클릭</button>
          </div>
      }

      countUp = (event) => {
        this.setState({
          count: this.state.count + 1
        })
      }
    }
    //출력하기
    const container = document.getElementById('root')
    ReactDOM.render(<App />, container)
  </script>
</body>
</html>

결과는 위와 같음

//입력 양식 사용하기
<!DOCTYPE html>
<html>
<head>
  <title>Document</title>
     <!--리액트 사용 준비-->
     <script src = "https://unpkg.com/react@17/umd/react.development.js"></script>
     <script src = "https://unpkg.com/react-dom@17/umd/react-dom.development.js"></script>
     <script src = "https://unpkg.com/babel-standalone@6/babel.min.js"></script>
</head>
<body>
  <div id ="root"></div>
  <script type ="text/babel">
    //애플리케이션 클래스 생성
    class App extends React.Component {
      constructor (props) {
        super(props)
        this.state = {
          text: ''
        }
        this.handleChange = this.handleChange.bind(this)
      }

      render() {
        return <div>
          <input
          value = {this.state.text}
          onChange = {this.handleChange} />
          <h1>{this.state.text}</h1>
        </div>
      }
      handleChange (event) {
        this.setState({
          text: event.target.value
        })
      }
    }
    //출력하기
    const container = document.getElementById('root')
    ReactDOM.render(<App />, container)
  </script>
</body>
</html>

 


 

 

스타일 지정하기

 

 스타일을 지정할 때는 style 속성에 객체를 지정.
render ( ) {
    const style = { }
    return <h1 style = {style} 글자 </h1> 
}

 

CSS 스타일 속성 이름 가능한 형태(1) 가능한 형태(2)
color : red
  color: 'red'
}

  'color' : 'red'
}
font-size : 2px
  fontSize: 2
}

  'font-size' : 2
}

크기 등의 단위는 숫자만 입력하면 됨. px를 붙이지 않아도 괜춘.

//체크 상태에 따라서 스타일 지정하기
<!DOCTYPE html>
<html>
<head>
  <title>Document</title>
     <!--리액트 사용 준비-->
     <script src = "https://unpkg.com/react@17/umd/react.development.js"></script>
     <script src = "https://unpkg.com/react-dom@17/umd/react-dom.development.js"></script>
     <script src = "https://unpkg.com/babel-standalone@6/babel.min.js"></script>
</head>
<body>
  <div id ="root"></div>
  <script type ="text/babel">
    //애플리케이션 클래스 생성
    class App extends React.Component {
      constructor (props) {
        super(props)
        this.state = {
          checked: false
        }
        this.handleClick = this.handleClick.bind(this)
      }

      render() {
        const textStyle = {
          colo : this.state.checked ? 'blue' : 'red'
        }

        return <div>
          <input
          type = "checkbox"
          onClick = {this.handleClick} />
          <h1 style = {textStyle}>글자</h1>
        </div>
      }
      handleClick (event) {
        this.setState({
          checked : event.target.checked
        })
      }
    }
    //출력하기
    const container = document.getElementById('root')
    ReactDOM.render(<App />, container)
  </script>
</body>
</html>

 

 

컴포넌트 배열
리액트는 컴포넌트를 요소로 갖는 배열을 사용해서 한 번에 여러 개의 컴포넌트를 출력할 수 있음.

//컴포넌트 배열 사용하기(1)
<!DOCTYPE html>
<html>
<head>
  <title>Document</title>
     <!--리액트 사용 준비-->
     <script src = "https://unpkg.com/react@17/umd/react.development.js"></script>
     <script src = "https://unpkg.com/react-dom@17/umd/react-dom.development.js"></script>
     <script src = "https://unpkg.com/babel-standalone@6/babel.min.js"></script>
</head>
<body>
  <div id ="root"></div>
  <script type ="text/babel">
    //애플리케이션 클래스 생성
    class App extends React.Component {
      render () {
       const list = [
        <li>사과</li>,
        <li>바나나</li>,
        <li>배</li>,
        <li>귤</li>
      ]
      
      return <ul>{list}</ul>
      }
    }

    //출력하기
    const container = document.getElementById('root')
    ReactDOM.render(<App />, container)
  </script>
</body>
</html>

 

//컴포넌트 배열 사용하기(2)
<!DOCTYPE html>
<html>
<head>
  <title>Document</title>
     <!--리액트 사용 준비-->
     <script src = "https://unpkg.com/react@17/umd/react.development.js"></script>
     <script src = "https://unpkg.com/react-dom@17/umd/react-dom.development.js"></script>
     <script src = "https://unpkg.com/babel-standalone@6/babel.min.js"></script>
</head>
<body>
  <div id ="root"></div>
  <script type ="text/babel">
    //애플리케이션 클래스 생성
    class App extends React.Component {
      constructor (props) {
        super(props)
        this.state = {
          fruits: ['사과','바나나','배','귤']
        }
      }

      render () {
        //항목을 생성
        const list = this.state.fruits.map((item) => {
          return <li>{item}</li>
        })
        //출력
        return <ul>{list}</ul>
      }
    }
    //출력하기
    const container = document.getElementById('root')
    ReactDOM.render(<App />, container)
  </script>
</body>
</html>

결과는 위의 코드와 같음. 

 

//컴포넌트  배열 사용하기(3)
<!DOCTYPE html>
<html>
<head>
  <title>Document</title>
     <!--리액트 사용 준비-->
     <script src = "https://unpkg.com/react@17/umd/react.development.js"></script>
     <script src = "https://unpkg.com/react-dom@17/umd/react-dom.development.js"></script>
     <script src = "https://unpkg.com/babel-standalone@6/babel.min.js"></script>
</head>
<body>
  <div id ="root"></div>
  <script type ="text/babel">
    //애플리케이션 클래스 생성
    class App extends React.Component {
      constructor (props) {
        super(props)
        this.state = {
          fruits: ['사과','바나나','배','귤']
        }
      }

      render () {
        return <ul>{
          this.state.fruits.map((item)=> {
            return <li>{item}</li>
          })
        }</ul>
      }
    }    
    //출력하기
    const container = document.getElementById('root')
    ReactDOM.render(<App />, container)
  </script>
</body>
</html>

결과는 위의 코드와 같음. 

 

리앤트와 데이터
여러 개의 컴포넌트 사용하기

//Item 컴포넌트 만들기
<!DOCTYPE html>
<html>
<head>
  <title>Document</title>
     <!--리액트 사용 준비-->
     <script src = "https://unpkg.com/react@17/umd/react.development.js"></script>
     <script src = "https://unpkg.com/react-dom@17/umd/react-dom.development.js"></script>
     <script src = "https://unpkg.com/babel-standalone@6/babel.min.js"></script>
</head>
<body>
  <div id ="root"></div>
  <script type ="text/babel">
    //애플리케이션 클래스 생성
    class App extends React.Component {
      render () {
        return <ul>
          <Item />
          <Item />
          <Item />
        </ul>
      }
    }
    class Item extends React.Component {
      render () {
        return <li>Item 컴포넌트 </li>
      }
    }
    //출력하기
    const container = document.getElementById('root')
    ReactDOM.render(<App />, container)
  </script>
</body>
</html>

 

App컴포넌트에서 Item 컴포넌트로 어떤 데이터를 전달하고 싶을 때는 컴포넌트의 속성을 사용함. 

 

//Item 컴포넌트에 속성 전달하기
<!DOCTYPE html>
<html>
<head>
  <title>Document</title>
     <!--리액트 사용 준비-->
     <script src = "https://unpkg.com/react@17/umd/react.development.js"></script>
     <script src = "https://unpkg.com/react-dom@17/umd/react-dom.development.js"></script>
     <script src = "https://unpkg.com/babel-standalone@6/babel.min.js"></script>
</head>
<body>
  <div id ="root"></div>
  <script type ="text/babel">
    //애플리케이션 클래스 생성
    class App extends React.Component {
      render () {
        return <ul>
          <Item value = "Item 컴포넌트 1번" />
          <Item value = "Item 컴포넌트 2번" />
          <Item value = "Item 컴포넌트 3번" />
          </ul>
        }
      }

      class Item extends React.Component {
        constructor(props) {
          super(props)
        }

        render () {
          return <li>{this.props.value}</li>
        }
      }
    //출력하기
    const container = document.getElementById('root')
    ReactDOM.render(<App />, container)
  </script>
</body>
</html>

App 컴포넌트에서 Item 컴포넌트로  value속성을 전달하고, Item 컴포넌트에서 value속성을 출력하는 예임.

 

부모에서 자식의 state 속성 변경하기

//부모에서 자식의 state 속성 변경하기
<!DOCTYPE html>
<html>
<head>
  <title>Document</title>
     <!--리액트 사용 준비-->
     <script src = "https://unpkg.com/react@17/umd/react.development.js"></script>
     <script src = "https://unpkg.com/react-dom@17/umd/react-dom.development.js"></script>
     <script src = "https://unpkg.com/babel-standalone@6/babel.min.js"></script>
</head>
<body>
  <div id ="root"></div>
  <script type ="text/babel">
    //애플리케이션 클래스 생성
    class App extends React.Component {
      constructor(props) {
        super(props)
        this.state = {
          time: new Date()
        }
      }

      componentDidMoundt () {
        //컴포넌트가 화면에 출력되었을 때
        this.timeId = setInterval(() => {
          this.setState({
            time:new Date()
          })
        }, 1000)
      }
      ComponentWillUnmount() {
        //컴포넌트가 화면에서 제거될 때
        clearInterval(this.timerId)
      }
      render() {
        return <ul>
          <Item value = {this.state.time.toLocaleString()} />
          <Item value = {this.state.time.toLocaleString()} />
          <Item value = {this.state.time.toLocaleString()} />
        </ul>
      }
    }
  
    class Item extends React.Component {
      constructor (props) {
        super(props)
        this.state = {
          value: props.value
        }
      }

      componentDidUpdate (prevProps) {
        if (prevProps.value !== this. props.value) {
          this.setState ({
            value: this.props.value
          })
        }
      }

      render() {
        return <li>{this.state.value}</li>
      }
    }
    //출력하기
    const container = document.getElementById('root')
    ReactDOM.render(<App />, container)
  </script>
</body>
</html>

 

 

 

 

    ㄴ componentDidUpdate( )메소드는 컴포넌트에 변경이 발생했을 때 호출되는 메소드로 이를 오버라이드해서 사용하고 있음. componentDidUpdate( ) 메소드는 매개변수로 변경 이전의 속성(prevProps)이 들어오며, 이 속성 값과 현재 속성 값을 비교해서 변경이 있는경우에만  setState( )메소드를 호출해서 화면에 변경사항을 출력. componentDidUpdate( ) 메소드 부분이 없음녀 시간은 변하지 않음. 

 

자식에서 부모의 state 속성 변경하기

반대로 자식 컴포넌트에서 부모 컴포넌트의 상태를 변경 할 때는 메소드를 사용. 부모 컴포넌트에서 자신(부모)의 속성을 변경하는 메소드를 자식에게 전달한 뒤,
자식에서 이를 호출하게 만드는 것임.

 

//자식에서 부모의 state 속성 변경하기
<!DOCTYPE html>
<html>
<head>
  <title>Document</title>
     <!--리액트 사용 준비-->
     <script src = "https://unpkg.com/react@17/umd/react.development.js"></script>
     <script src = "https://unpkg.com/react-dom@17/umd/react-dom.development.js"></script>
     <script src = "https://unpkg.com/babel-standalone@6/babel.min.js"></script>
</head>
<body>
  <div id ="root"></div>
  <script type ="text/babel">
    //애플리케이션 클래스 생성
    class App extends React.Component {
      constructor(props) {
        super(props)
        this.state = {
          value : ''
        }
        this.changeParent = this.changeParent.bind(this)
      }

      render () {
        return <div>
          <CustomInput onChange = {this.changeParent} />
          <h1>{this.state.value}</h1>
          </div>
      }

      changeParent (event) {
        this.setState ({
          value : event.target.value
        })
      }
    }

    class CustomInput extends React.Component {
      render () {
        return <div>
          <input onChange = {this.props.onChange} />
          </div>
      }
    }
    
    //출력하기
    const container = document.getElementById('root')
    ReactDOM.render(<App />, container)
  </script>
</body>
</html>

 

예제1) 리액트로 만드는 할 일 목록 애플리케이션

 

<!DOCTYPE html>
<html>
<head>
  <title>Document</title>
     <!--리액트 사용 준비-->
     <script src = "https://unpkg.com/react@17/umd/react.development.js"></script>
     <script src = "https://unpkg.com/react-dom@17/umd/react-dom.development.js"></script>
     <script src = "https://unpkg.com/babel-standalone@6/babel.min.js"></script>
</head>
<body>
  <div id ="root"></div>
  <script type ="text/babel">
    //애플리케이션 클래스 생성
    class App extends React.Component {
      constructor (props) {
        super(props)

        //지난 설정 불러오기
        this.state = this.load()

        //메소드 바인드
        this.textChange = this.textChange.bind(this)
        this.textKeyDown = this.textKeyDown.bind(this)
        this.buttonClick = this.buttonClick.bind(this)
        this.removeItem = this.removeItem.bind(this)
        this.changeCheckData = this.changeCheckData.bind(this)
      }

      save () {
        localStorage.state = JSON.stringify(this.state)
      }
      load () {
        let output
        try { output = JSON.parse(localStorage.state)
        } catch (e) {}
        if (output !== undefined
        && output.keyCount !== undefined
        && output.currentValue !== undefined)
        { 
          output = JSON.parse(localStorage.state)
        } else {
          output = {
            keyCount : 0,
            currentValue : '',
            todos: []
          }
        }
        return output
      }

      componentDidUpdate() {
        this.save()
      }

      render () {
        return <div>
          <h1>할 일 목록</h1>
          <Input
            value = {this.state.currentValue}
            onChange = {this.textChange}
            onKeyDown = {this.textKeyDown}/>
          <button onClick = {this.buttonClick}>추가하기</button>
          <div>
            {this.state.todos.map((todo)=> {
              return <TodoItem
                dataKey = {todo.key}
                isDone = {todo.isDone}
                text = {todo.text}
                removeItem = {this.removeItem}
                changeCheckData = {this.chagngeCheckData} />
            })}
            </div>
          </div>
        }

      textChange (event) {
        this.setState({
          currentValue: event.target.value
        })
      }

      textKeyDown (event) {
        const ENTER = 13
        if (event.keyCode === ENTER) {
          this.buttonClick()
        }
      }

      buttonClick (event) {
        if (this.state.currentValue.trim() !== '') {
          this.setState ({
            todos: [...this.state.todos, {
              key: this.state.keyCount.toStirng(),
              isDone: false,
              text: this.state.currentValue
            }]
          })
          this.state.keyCount += 1
          this.state.currentValue = ''
        }
      }

      removeItem(key) {
        this.setState({
          todos: this.state.todos.filter((todo) => {
            return todo.key !== key
          })
        })
      }

      changeCheckData (key, changed) {
        let target = [...this.state.todos]
        target.filter((todo) => todo.key === key)[0].isDone = changed
        this.setState({
          todos: target
        })
      }
    }

    class TodoItem extends React.Component {
      constructor (props) {
        super(props)
        this.state = {
          isDone: props.isDone
        }
        this.checkboxClick = this.checkboxClick.bind(this)
      }

      render () {
        const textStyle = {}
        textStyle.textDecoration 
          = this.state.isDone ? 'line-through' : ''
        return (
          <div style = {textStyle}>
            <Input
              type = "checkbox"
              checked = {this.state.isDone}
              onChange = {this.checkboxClick} />

              <span>{this.props.text}</span>
              <button onClick={() => this.props.removeItem(this.props.dataKey)}>제거</button>
          </div>
        )
      }

      checkboxClick () {
        const changed = !this.state.isDone
        this.props.changeCheckData(this.props.dataKey, changed)
      }

      componentDidUpdate(prevProps) {
        if (prevProps.isDone !== this.props.isDone) {
          this.setState ({
            isDone: this.props.isDone
          })
        }
      }
    }
    //출력하기
    const container = document.getElementById('root')
    ReactDOM.render(<App />, container)
  </script>
</body>
</html>

책보고 친건데...몇 번을 봐도 오류가 뜬다...좀 더 찾아봐야겠다

'IT > 자바스크립트' 카테고리의 다른 글

[혼공자스]09.클래스  (0) 2022.12.05
[혼공자스] 08. 예외처리  (0) 2022.12.05
[혼공자스] 07.문서 객체 모델  (0) 2022.12.05
[혼공자스] 06. 객체  (0) 2022.11.18
자바스크립트 실수 모음집  (0) 2022.11.18
Comments