Notice
Recent Posts
Recent Comments
Link
«   2024/11   »
1 2
3 4 5 6 7 8 9
10 11 12 13 14 15 16
17 18 19 20 21 22 23
24 25 26 27 28 29 30
Tags
more
Archives
Today
Total
관리 메뉴

개발자입니다

[React] 예제 소스 정리 - React 본문

네이버클라우드 AIaaS 개발자 양성과정 1기/React

[React] 예제 소스 정리 - React

끈기JK 2023. 3. 14. 20:11

eomcs-java\eomcs-web\app\src\main\resources\static\react\ex01~10

 

 

예제 소스 정리

 

 

react

 

 

resources\react\ex01

 

 

빌드 도구 없이 사용하기
<!-- ex01/test1.html -->
<!DOCTYPE html>
<html>
  <head>
    <meta charset="UTF-8" />
    <title>React</title>
  </head>
  <body>

    <h2>빌드 도구 없이 사용하기</h2>

    <div id="like_button_container"></div>

    <script src="https://unpkg.com/react@18/umd/react.development.js" crossorigin></script>
    <script src="https://unpkg.com/react-dom@18/umd/react-dom.development.js" crossorigin></script>

    <script src="test1.js"></script>
  </body>
</html>
// ex01/test1.js
'use strict';

class LikeButton extends React.Component {
  constructor(props) {
    super(props);
    this.state = { liked: false };
  }

  render() {
    if (this.state.liked) {
      return 'You liked this.';
    }

    return React.createElement(
      'button',
      { onClick: () => this.setState({ liked: true }) },
      'Like'
    );
  }
} 

const domContainer = document.querySelector('#like_button_container');
const root = ReactDOM.createRoot(domContainer);
root.render(React.createElement(LikeButton));

 

 

리액트 컴포넌트 재사용
<!-- ex01/test2.html -->
<!DOCTYPE html>
<html>
  <head>
    <meta charset="UTF-8" />
    <title>React</title>
  </head>
  <body>

    <h2>리액트 컴포넌트 재사용</h2>

    <div class="like_button_container" data-commentid="1"></div>
    <div class="like_button_container" data-commentid="2"></div>
    <div class="like_button_container" data-commentid="3"></div>

    <script src="https://unpkg.com/react@18/umd/react.development.js" crossorigin></script>
    <script src="https://unpkg.com/react-dom@18/umd/react-dom.development.js" crossorigin></script>

    <script src="test2.js"></script>
  </body> 
</html>

 

React.Component 클래스에 변수 state 가 선언되어 있다. 이 클래스를 상속받아 LikeButton 을 정의한다.

state 는 값을 객체로 저장하기 위한 저장소이다. read/write 가능하다.

props 도 저장소이나 readonly 이다.

React.createElement(태그명, 속성정보) 로 객체 생성 및 값 전달한다.

// ex01/test2.js
'use strict';

class LikeButton extends React.Component {
  constructor(props) {
    super(props);
    this.state = { liked: false };
  }

  render() {
    if (this.state.liked) {
      return 'You liked comment number ' + this.props.commentid;
    }

    return React.createElement(
      'button',
      { onClick: () => this.setState({ liked: true }) },
      'Like'
    );
  }
} 

document.querySelectorAll('.like_button_container')
  .forEach(container => {
    const commentid = parseInt(container.dataset.commentid, 10);
    const root = ReactDOM.createRoot(container);
    root.render(
      React.createElement(LikeButton, {commentid: commentid})
    );
  });

 

 

배포용 라이브러리 + 자바스크립트 코드 압축
<!-- ex01/test3.html -->
<!DOCTYPE html>
<html>
  <head>
    <meta charset="UTF-8" />
    <title>React</title>
  </head>
  <body>

    <h2>배포용 라이브러리 + 자바스크립트 코드 압축</h2>

    <div class="like_button_container" data-commentid="1"></div>
    <div class="like_button_container" data-commentid="2"></div>
    <div class="like_button_container" data-commentid="3"></div>

    <!-- 개발 완료 후 -->
    <script src="https://unpkg.com/react@18/umd/react.production.min.js" crossorigin></script>
    <script src="https://unpkg.com/react-dom@18/umd/react-dom.production.min.js" crossorigin></script>

    <!--
      npx(node package executor)
      $ npx terser test2.js -c -m -o test2.min.js 
      기본: whitespace(빈공간,탭,줄바꿈) 제거
      -c, --compress : console.log() 와 같은 불필요한 함수 제거
      -m, --mangle :  변수명 줄임
      -o, --output <파일명> : 압축한 후 생성될 파일명 지정
    -->
    <script src="test2.min.js"></script>
  </body> 
</html>
// ex01/test2.min.js
"use strict";class LikeButton extends React.Component{constructor(e){super(e),this.state={liked:!1}}render(){return this.state.liked?"You liked comment number "+this.props.commentid:React.createElement("button",{onClick:()=>this.setState({liked:!0})},"Like")}}document.querySelectorAll(".like_button_container").forEach((e=>{const t=parseInt(e.dataset.commentid,10);ReactDOM.createRoot(e).render(React.createElement(LikeButton,{commentid:t}))}));

 

 

JSX 사용
<!-- ex01/test4.html -->
<!DOCTYPE html>
<html>
  <head>
    <meta charset="UTF-8" />
    <title>React</title>
  </head>
  <body>

    <h2>JSX 사용</h2>

    <div class="like_button_container" data-commentid="1"></div>
    <div class="like_button_container" data-commentid="2"></div>
    <div class="like_button_container" data-commentid="3"></div>

    <script src="https://unpkg.com/react@18/umd/react.development.js" crossorigin></script>
    <script src="https://unpkg.com/react-dom@18/umd/react-dom.development.js" crossorigin></script>
    <script src="https://unpkg.com/babel-standalone@6/babel.min.js"></script>

    <script src="test4.js" type="text/babel"></script>
  </body> 
</html>

 

container.dataset 은 html 에서 data- 속성을 가져온다.

// ex01/test4.js
'use strict';

class LikeButton extends React.Component {
  constructor(props) {
    super(props);
    this.state = { liked: false };
  }

  render() {
    if (this.state.liked) {
      return 'You liked comment number ' + this.props.commentid;
    }

    return (
      <button onClick={() => this.setState({ liked: true })}>
        Like
      </button>
    );
  }
} 

document.querySelectorAll('.like_button_container')
  .forEach(container => {
    const commentid = parseInt(container.dataset.commentid, 10);
    const root = ReactDOM.createRoot(container);
    root.render(
      React.createElement(LikeButton, {commentid: commentid})
    );
  });

 

 

JSX 전처리기 사용
<!-- ex01/index.html -->
<!DOCTYPE html>
<html>
  <head>
    <meta charset="UTF-8" />
    <title>React</title>
  </head>
  <body>

    <h2>JSX 전처리기 사용</h2>

    <div class="like_button_container" data-commentid="1"></div>
    <div class="like_button_container" data-commentid="2"></div>
    <div class="like_button_container" data-commentid="3"></div>

    <script src="https://unpkg.com/react@18/umd/react.development.js" crossorigin></script>
    <script src="https://unpkg.com/react-dom@18/umd/react-dom.development.js" crossorigin></script>
    <script src="https://unpkg.com/babel-standalone@6/babel.min.js"></script>

    <!--
      JSX 전처리기 설정하기
      => $ npm install babel-cli@6 babel-preset-react-app@3

      JSX 감시기 실행
      => $ npx babel --watch src --out-dir . --presets react-app/prod
      => src 폴더의 .js 파일을 파싱하여 JSX 코드를 자바스크립트 코드로 바꾼 파일을  
         현재 폴더에 생성한다.
    -->
    <script src="test5.js"></script>
  </body> 
</html>
// ex01/src/test5.js
'use strict';

class LikeButton extends React.Component {
  constructor(props) {
    super(props);
    this.state = { liked: false };
  }

  render() {
    if (this.state.liked) {
      return 'You liked : ' + this.props.commentid;
    }

    return (
      <button onClick={() => this.setState({ liked: true })}>
        Like
      </button>
    );
  }
} 

document.querySelectorAll('.like_button_container')
  .forEach(container => {
    const commentid = parseInt(container.dataset.commentid, 10);
    const root = ReactDOM.createRoot(container);
    root.render(
      React.createElement(LikeButton, {commentid: commentid})
    );
  });
// ex01/test5.js
'use strict';

var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();

function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }

function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; }

function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; }

var LikeButton = function (_React$Component) {
  _inherits(LikeButton, _React$Component);

  function LikeButton(props) {
    _classCallCheck(this, LikeButton);

    var _this = _possibleConstructorReturn(this, (LikeButton.__proto__ || Object.getPrototypeOf(LikeButton)).call(this, props));

    _this.state = { liked: false };
    return _this;
  }

  _createClass(LikeButton, [{
    key: 'render',
    value: function render() {
      var _this2 = this;

      if (this.state.liked) {
        return 'You liked : ' + this.props.commentid;
      }

      return React.createElement(
        'button',
        { onClick: function onClick() {
            return _this2.setState({ liked: true });
          } },
        'Like'
      );
    }
  }]);

  return LikeButton;
}(React.Component);

document.querySelectorAll('.like_button_container').forEach(function (container) {
  var commentid = parseInt(container.dataset.commentid, 10);
  var root = ReactDOM.createRoot(container);
  root.render(React.createElement(LikeButton, { commentid: commentid }));
});

 

 

resources\react\ex02

 

 

<!-- index.html -->
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>ex02</title>
  </head>
  <body>
    <h2>JSX</h2>

    <div id="root"></div>

    <script src="https://unpkg.com/react@18/umd/react.development.js" crossorigin></script>
    <script src="https://unpkg.com/react-dom@18/umd/react-dom.development.js" crossorigin></script>
    <script src="https://unpkg.com/babel-standalone@6/babel.min.js"></script>

    <script src="test*.js"></script>
  </body>
</html>

 

 

JSX 시작!
// ex02/src/test1.js
"use strict";

// JSX 시작!
const root = ReactDOM.createRoot(document.getElementById("root"));
root.render(<h1>Hello, world!</h1>);
// ex02/test1.js
"use strict";

// JSX 시작!

var root = ReactDOM.createRoot(document.getElementById("root"));
root.render(React.createElement(
  "h1",
  null,
  "Hello, world!"
));

 

 

JSX 표현식
// ex02/src/test2.js
"use strict";

// JSX 표현식
const username = "홍길동";
const element = <h1>Hello, {username}</h1>;

const root = ReactDOM.createRoot(document.getElementById("root"));
root.render(element);
// ex02/test2.js
"use strict";

// JSX 표현식

var username = "홍길동";
var element = React.createElement(
  "h1",
  null,
  "Hello, ",
  username
);

var root = ReactDOM.createRoot(document.getElementById("root"));
root.render(element);

 

 

JSX {모든 자바스크립트 표현식} 기능
// ex02/src/test3.js
"use strict";

// JSX {모든 자바스크립트 표현식} 기능
function formatName(user) {
  return user.firstName + " " + user.lastName;
}
const user = {
  firstName: "길동",
  lastName: "홍",
};
const element = <h1>Hello, {formatName(user)}!</h1>;

const root = ReactDOM.createRoot(document.getElementById("root"));
root.render(element);
// ex02/test3.js
"use strict";

// JSX {모든 자바스크립트 표현식} 기능

function formatName(user) {
  return user.firstName + " " + user.lastName;
}
var user = {
  firstName: "길동",
  lastName: "홍"
};
var element = React.createElement(
  "h1",
  null,
  "Hello, ",
  formatName(user),
  "!"
);

var root = ReactDOM.createRoot(document.getElementById("root"));
root.render(element);

 

 

JSX 리턴
// ex02/src/test4.js
"use strict";

// JSX 리턴
function getGreeting(user) {
  if (user) {
    return <h1>Hello, {formatName(user)}!</h1>;
  }
  return <h1>Hello!</h1>;
}
function formatName(user) {
  return user.firstName + " " + user.lastName;
}
const user = {
  firstName: "길동",
  lastName: "홍",
};

const root = ReactDOM.createRoot(document.getElementById("root"));
root.render(getGreeting(user));
// ex02/test4.js
"use strict";

// JSX 리턴

function getGreeting(user) {
  if (user) {
    return React.createElement(
      "h1",
      null,
      "Hello, ",
      formatName(user),
      "!"
    );
  }
  return React.createElement(
    "h1",
    null,
    "Hello!"
  );
}
function formatName(user) {
  return user.firstName + " " + user.lastName;
}
var user = {
  firstName: "길동",
  lastName: "홍"
};

var root = ReactDOM.createRoot(document.getElementById("root"));
root.render(getGreeting(user));

 

 

JSX 속성 및 자식 태그
// ex02/src/test5.js
"use strict";

// JSX 속성 및 자식 태그
const url = "https://github.com";
const element = (
  <div>
    <a href='https://github.com'>문자열 링크</a>
    <br />
    <a href={url}>표현식 링크</a>
  </div>
);
const root = ReactDOM.createRoot(document.getElementById("root"));
root.render(element);
// ex02/test5.js
"use strict";

// JSX 속성 및 자식 태그

var url = "https://github.com";
var element = React.createElement(
  "div",
  null,
  React.createElement(
    "a",
    { href: "https://github.com" },
    "\uBB38\uC790\uC5F4 \uB9C1\uD06C"
  ),
  React.createElement("br", null),
  React.createElement(
    "a",
    { href: url },
    "\uD45C\uD604\uC2DD \uB9C1\uD06C"
  )
);
var root = ReactDOM.createRoot(document.getElementById("root"));
root.render(element);

 

 

JSX 속성 및 자식 태그
// ex02/src/test6.js
"use strict";

// JSX 속성 및 자식 태그
const title = "</h1><h1>삽입공격방지!</h1>";
const element = <h1>{title}</h1>; // 태그 문법을 일반 문자열로 취급함!

const root = ReactDOM.createRoot(document.getElementById("root"));
root.render(element);
// ex02/test6.js
"use strict";

// JSX 속성 및 자식 태그

var title = "</h1><h1>삽입공격방지!</h1>";
var element = React.createElement(
  "h1",
  null,
  title
); // 태그 문법을 일반 문자열로 취급함!

var root = ReactDOM.createRoot(document.getElementById("root"));
root.render(element);

 

 

resources\react\ex03

 

 

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>ex03</title>
  </head>
  <body>
    <h2>React element 렌더링</h2>

    <div id="root"></div>

    <script src="https://unpkg.com/react@18/umd/react.development.js" crossorigin></script>
    <script src="https://unpkg.com/react-dom@18/umd/react-dom.development.js" crossorigin></script>
    <script src="https://unpkg.com/babel-standalone@6/babel.min.js"></script>

    <script src="test3.js"></script>
  </body>
</html>

 

 

DOM element vs React element
// ex03/src/test1.js
"use strict";

// DOM element vs React element
const element = <h1>Hello, world!</h1>;
const root = ReactDOM.createRoot(document.getElementById("root"));
root.render(element);
// ex03/test1.js
"use strict";

// DOM element vs React element

var element = React.createElement(
  "h1",
  null,
  "Hello, world!"
);
var root = ReactDOM.createRoot(document.getElementById("root"));
root.render(element);

 

 

React element 업데이트하기
// ex03/src/test2.js
"use strict";

// React element 업데이트하기
const root = ReactDOM.createRoot(document.getElementById("root"));

function tick() {
  const element = (
    <div>
      <h1>Hello, world!</h1>
      <h2>It is {new Date().toLocaleTimeString()}.</h2>
    </div>
  );
  root.render(element);
  // 코드는 전체 UI를 다시 그리는 것이지만,
  // React DOM은 변경된 텍스트 노드만 다시 그린다.
  // 개발자 도구의 Element를 확인해보라!
}

setInterval(tick, 1000);
// ex03/test2.js
"use strict";

// React element 업데이트하기

var root = ReactDOM.createRoot(document.getElementById("root"));

function tick() {
  var element = React.createElement(
    "div",
    null,
    React.createElement(
      "h1",
      null,
      "Hello, world!"
    ),
    React.createElement(
      "h2",
      null,
      "It is ",
      new Date().toLocaleTimeString(),
      "."
    )
  );
  root.render(element);
  // 코드는 전체 UI를 다시 그리는 것이지만,
  // React DOM은 변경된 텍스트 노드만 다시 그린다.
  // 개발자 도구의 Element를 확인해보라!
}

setInterval(tick, 1000);

 

 

클래스 컴포넌트 만들기
// ex03/src/test3.js
"use strict";

// 클래스 컴포넌트 만들기
// => 컴포넌트의 이름은 항상 대문자로 시작한다.
class Welcome extends React.Component {
  render() {
    return <h1>Hello, {this.props.name}</h1>;
  }
}

// welcome 클래스의 설계도에 따라 React element 객체를 생성한다.
const element = <Welcome name="임꺽정" />;

const root = ReactDOM.createRoot(document.getElementById("root"));
root.render(element);
// ex03/test3.js
"use strict";

// 클래스 컴포넌트 만들기
// => 컴포넌트의 이름은 항상 대문자로 시작한다.

var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();

function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }

function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; }

function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; }

var Welcome = function (_React$Component) {
  _inherits(Welcome, _React$Component);

  function Welcome(props) {
    _classCallCheck(this, Welcome);

    return _possibleConstructorReturn(this, (Welcome.__proto__ || Object.getPrototypeOf(Welcome)).call(this, props));
  }

  _createClass(Welcome, [{
    key: "render",
    value: function render() {
      return React.createElement(
        "h1",
        null,
        "Hello, ",
        this.props.name
      );
    }
  }]);

  return Welcome;
}(React.Component);

var element = React.createElement(Welcome, { name: "\uC784\uAEBD\uC815" });

var root = ReactDOM.createRoot(document.getElementById("root"));
root.render(element);

 

 

함수 컴포넌트 만들기
// ex03/src/test4.js
"use strict";

// 함수 컴포넌트 만들기
// => 컴포넌트의 이름은 항상 대문자로 시작한다.
function Welcome(props) {
  return <h1>Hello, {props.name}</h1>;
}

// Welcome() 함수를 통해 DOM 엘리먼트를 생성할 리액트 컴포넌트(엘리먼트)를 만든다.
const element = <Welcome name='홍길동' />;

const root = ReactDOM.createRoot(document.getElementById("root"));
root.render(element);
// ex03/test4.js
"use strict";

// 함수 컴포넌트 만들기
// => 컴포넌트의 이름은 항상 대문자로 시작한다.

function Welcome(props) {
  return React.createElement(
    "h1",
    null,
    "Hello, ",
    props.name
  );
}

var element = React.createElement(Welcome, { name: "\uD64D\uAE38\uB3D9" });

var root = ReactDOM.createRoot(document.getElementById("root"));
root.render(element);

 

 

컴포넌트 합성
// ex03/src/test5.js
"use strict";

// 컴포넌트 합성
// => 다른 컴포넌트를 참조 할 수 있다.
function Welcome(props) {
  return <h1>Hello, {props.name}</h1>;
}

function App() {
  return (
    <div>
      <Welcome name='홍길동' />
      <Welcome name='임꺽정' />
      <Welcome name='유관순' />
    </div>
  );
}

const element = <Welcome name='홍길동' />;

const root = ReactDOM.createRoot(document.getElementById("root"));
root.render(App());
// ex03/test5.js
"use strict";

// 컴포넌트 합성
// => 다른 컴포넌트를 참조 할 수 있다.

function Welcome(props) {
  return React.createElement(
    'h1',
    null,
    'Hello, ',
    props.name
  );
}

function App() {
  return React.createElement(
    'div',
    null,
    React.createElement(Welcome, { name: '\uD64D\uAE38\uB3D9' }),
    React.createElement(Welcome, { name: '\uC784\uAEBD\uC815' }),
    React.createElement(Welcome, { name: '\uC720\uAD00\uC21C' })
  );
}

var element = React.createElement(Welcome, { name: '\uD64D\uAE38\uB3D9' });

var root = ReactDOM.createRoot(document.getElementById("root"));
root.render(App());

 

 

resources\react\ex04

 

 

<!-- index.html -->
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>ex04</title>
  </head>
  <body>
    <h2>State 다루기</h2>

    <div id="root"></div>

    <script src="https://unpkg.com/react@18/umd/react.development.js" crossorigin></script>
    <script src="https://unpkg.com/react-dom@18/umd/react-dom.development.js" crossorigin></script>
    <script src="https://unpkg.com/babel-standalone@6/babel.min.js"></script>

    <script src="test8.js"></script>
  </body>
</html>

 

 

1단계: 함수 컴포넌트 사용 전
// src/test1.js
"use strict";

// 1단계: 함수 컴포넌트 사용 전
const root = ReactDOM.createRoot(document.getElementById("root"));

function tick() {
  const element = (
    <div>
      <h1>Hello, world!</h1>
      <h2>It is {new Date().toLocaleTimeString()}.</h2>
    </div>
  );
  root.render(element);
}

setInterval(tick, 1000);
// ex04/test1.js
"use strict";

// 1단계: 함수 컴포넌트 사용 전

var root = ReactDOM.createRoot(document.getElementById("root"));

function tick() {
  var element = React.createElement(
    "div",
    null,
    React.createElement(
      "h1",
      null,
      "Hello, world!"
    ),
    React.createElement(
      "h2",
      null,
      "It is ",
      new Date().toLocaleTimeString(),
      "."
    )
  );
  root.render(element);
}

setInterval(tick, 1000);

 

 

2단계: 함수 컴포넌트 사용 후
// ex04/src/test2.js
"use strict";

// 2단계: 함수 컴포넌트 사용 후
const root = ReactDOM.createRoot(document.getElementById("root"));

function Clock(props) {
  return (
    <div>
      <h1>Hello, world!</h1>
      <h2>It is {props.date.toLocaleTimeString()}.</h2>
    </div>
  );
}

function tick() {
  root.render(<Clock date={new Date()} />);
}

setInterval(tick, 1000);
// test2.js
"use strict";

// 2단계: 함수 컴포넌트 사용 후

var root = ReactDOM.createRoot(document.getElementById("root"));

function Clock(props) {
  return React.createElement(
    "div",
    null,
    React.createElement(
      "h1",
      null,
      "Hello, world!"
    ),
    React.createElement(
      "h2",
      null,
      "It is ",
      props.date.toLocaleTimeString(),
      "."
    )
  );
}

function tick() {
  root.render(React.createElement(Clock, { date: new Date() }));
}

setInterval(tick, 1000);

 

 

3단계: 클래스 컴포넌트 사용
// ex04/src/test3.js
"use strict";

// 3단계: 클래스 컴포넌트 사용
const root = ReactDOM.createRoot(document.getElementById("root"));

class Clock extends React.Component {
  render() {
    return (
      <div>
        <h1>Hello, world!</h1>
        <h2>It is {this.props.date.toLocaleTimeString()}.</h2>
      </div>
    );
  }
}

function tick() {
  root.render(<Clock date={new Date()} />);
}

setInterval(tick, 1000);

 

 

4단계: 클래스 컴포넌트 사용 + State
// ex04/src/test3.js
"use strict";

// 4단계: 클래스 컴포넌트 사용 + State
const root = ReactDOM.createRoot(document.getElementById("root"));

class Clock extends React.Component {
  constructor(props) {
    super(props);
    this.state = { date: new Date() };
  }
  render() {
    return (
      <div>
        <h1>Hello, world!</h1>
        <h2>It is {this.state.date.toLocaleTimeString()}.</h2>
      </div>
    );
  }
}

root.render(<Clock />);

 

 

5단계: 클래스 컴포넌트 사용 + State + Lifecycle
// ex04/src/test5.js
"use strict";

// 5단계: 클래스 컴포넌트 사용 + State + Lifecycle
const root = ReactDOM.createRoot(document.getElementById("root"));

class Clock extends React.Component {
  constructor(props) {
    super(props);
    this.state = { date: new Date() };
  }

  // DOM 에 렌더링 될 때 호출됨
  componentDidMount() {
    console.log("ok");
  }

  // 렌더링된 DOM이 삭제될 때 호출됨
  componentWillUnmount() {
    console.log("no");
  }

  render() {
    return (
      <div>
        <h1>Hello, world!</h1>
        <h2>It is {this.state.date.toLocaleTimeString()}.</h2>
      </div>
    );
  }
}

root.render(<Clock />);

 

 

6단계: 클래스 컴포넌트 사용 + State + Lifecycle(타이머설정/해제)
// ex04/src/test6.js
"use strict";

// 6단계: 클래스 컴포넌트 사용 + State + Lifecycle(타이머설정/해제)
const root = ReactDOM.createRoot(document.getElementById("root"));

class Clock extends React.Component {
  constructor(props) {
    super(props);

    // 보통 생성자에서 객체의 상태를 초기화시킨다.
    this.state = { date: new Date() };
  }

  // DOM 에 렌더링 될 때 호출됨
  componentDidMount() {
    this.timerID = setInterval(() => this.tick(), 1000);
  }

  // 렌더링된 DOM이 삭제될 때 호출됨
  componentWillUnmount() {
    clearInterval(this.timerID);
  }

  tick() {
    console.log("tick!!!");
    // 직접 state의 프로퍼티 값을 변경하면 다시 렌더링하지 않는다.
    this.state.date = new Date();

    // 반드시 setState()를 호출하여 state의 프로퍼티를 변경해야만 다시 렌더링 한다.
    // setState()를 UI 컴포넌트 상태를 변경하면 render() 메서드가 다시 호출된다.
    // => 컴포넌트 상태를 변경하면 UI에 반영하기 위해 render()가 자동 호출된다.
    // this.setState({
    //   date: new Date(),
    // });
  }

  render() {
    return (
      <div>
        <h1>Hello, world!</h1>
        <h2>It is {this.state.date.toLocaleTimeString()}.</h2>
      </div>
    );
  }
}

root.render(<Clock />);

 

 

7단계: 클래스 컴포넌트 사용 + State + Lifecycle(타이머설정/해제) + 자식 컴포넌트
// ex04/src/test7.js
"use strict";

// 7단계: 클래스 컴포넌트 사용 + State + Lifecycle(타이머설정/해제) + 자식 컴포넌트
const root = ReactDOM.createRoot(document.getElementById("root"));

// 데이터는 "하향식(top-down)" 또는 "단방향식"으로 흐른다.
function FormattedDate(props) {
  return <h2>It is {props.date.toLocaleTimeString()}.</h2>;
}

class Clock extends React.Component {
  constructor(props) {
    super(props);
    this.state = { date: new Date() };
  }

  componentDidMount() {
    this.timerID = setInterval(() => this.tick(), 1000);
  }

  componentWillUnmount() {
    clearInterval(this.timerID);
  }

  tick() {
    this.setState({
      date: new Date(),
    });
  }

  render() {
    return (
      <div>
        <h1>Hello, world!</h1>
        <FormattedDate date={this.state.date} />
      </div>
    );
  }
}

root.render(<Clock />);

 

 

8단계: 클래스 컴포넌트 사용 + State + Lifecycle(타이머설정/해제) + 자식 컴포넌트 + 여러 개
// ex04/src/test8.js
"use strict";

// 8단계: 클래스 컴포넌트 사용 + State + Lifecycle(타이머설정/해제) + 자식 컴포넌트 + 여러 개
const root = ReactDOM.createRoot(document.getElementById("root"));

function FormattedDate(props) {
  return <h2>It is {props.date.toLocaleTimeString()}.</h2>;
}

class Clock extends React.Component {
  constructor(props) {
    super(props);
    this.state = { date: new Date() };
  }

  componentDidMount() {
    this.timerID = setInterval(
      () => this.tick(),
      parseInt(Math.random() * 3000)
    );
  }

  componentWillUnmount() {
    clearInterval(this.timerID);
  }

  tick() {
    this.setState({
      date: new Date(),
    });
  }

  render() {
    return (
      <div>
        <h1>Hello, world!</h1>
        <FormattedDate date={this.state.date} />
      </div>
    );
  }
}

// 모든 컴포넌트가 독립적이다!
function App() {
  return (
    <div>
      <Clock />
      <Clock />
      <Clock />
    </div>
  );
}
root.render(App());

 

 

resources\react\ex05

 

 

<!-- index.html -->
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>ex05</title>
  </head>
  <body>
    <h2>이벤트 처리하기</h2>

    <div id="root"></div>

    <script
      src="https://unpkg.com/react@18/umd/react.development.js"
      crossorigin
    ></script>
    <script
      src="https://unpkg.com/react-dom@18/umd/react-dom.development.js"
      crossorigin
    ></script>
    <script src="https://unpkg.com/babel-standalone@6/babel.min.js"></script>

    <script src="test4.js"></script>
  </body>
</html>

 

 

이벤트 리스너 등록하기
// ex05/src/test1.js
"use strict";

// 이벤트 리스너 등록하기

class Toggle extends React.Component {
  constructor(props) {
    super(props);
    this.state = { isToggleOn: true };

    // handleClick() 함수의 this가 이 객체를 가리키도록 묶어 준다.
    this.handleClick = this.handleClick.bind(this);
  }

  handleClick() {
    // 방법1)
    // this.setState({
    //   isToggleOn: !this.state.isToggleOn,
    // });

    // 방법2) setState()에 객체를 넘기지 않고 함수를 넘긴다.
    // setState()가 함수를 파라미터로 받으면
    // 해당 함수 호출하여 그 리턴 값을 사용한다.
    // 함수를 호출할 때 현재 state 객체를 아규먼트로 넘겨준다.
    this.setState((currState) => ({
      isToggleOn: !currState.isToggleOn,
    }));
  }

  render() {
    return (
      <button onClick={this.handleClick}>
        {this.state.isToggleOn ? "ON" : "OFF"}
      </button>
    );
  }
}

const root = ReactDOM.createRoot(document.getElementById("root"));
root.render(<Toggle />);

 

 

bind() 사용 전
// ex05/src/test2.js
"use strict";

// bind() 사용 전

var obj1 = {
  title: "Hello!",
};

var obj2 = {
  title: "World!",
  getTitle: function () {
    return this.title;
  },
};

// obj2.getTitle()의 this가 가리키는 객체를 지정해 두지 않으면
// 호출 시점에서 this가 가리키는 객체를 사용한다.
// obj1.m = obj2.getTitle;

// obj2.getTitle()의 this가 가리키는 객체를 지정해 두면
// getTitle()을 어디에 붙여서 호출하든 간에 this는 처음에 지정한 객체를 가리킨다.
obj1.m = obj2.getTitle.bind(obj2);

class Box extends React.Component {
  render() {
    return <p>title: {obj1.m()}</p>;
  }
}

const root = ReactDOM.createRoot(document.getElementById("root"));
root.render(<Box />);

 

 

이벤트 리스너 등록하기
// ex05/src/test3.js
"use strict";

// 이벤트 리스너 등록하기

class Toggle extends React.Component {
  constructor(props) {
    super(props);
    this.state = { isToggleOn: true };
  }

  // 인스턴스 필드에 arrow function을 할당하면
  // this를 명시적으로 bind 할 필요가 없다.
  handleClick = () => {
    // arrow function에는 빌트인 변수 this, arguments, super 가 없다.
    // 따라서 클로저 입장에서 바깥 변수 this를 따로 복제해 둔다.
    // 이것을 보통 '바인드(bind) 한다'라고 표현한다.
    this.setState((prevState) => ({
      isToggleOn: !prevState.isToggleOn,
    }));
  };

  render() {
    return (
      <button onClick={this.handleClick}>
        {this.state.isToggleOn ? "ON" : "OFF"}
      </button>
    );
  }
}

const root = ReactDOM.createRoot(document.getElementById("root"));
root.render(<Toggle />);

 

 

이벤트 리스너 등록하기
// ex05/src/test4.js
"use strict";

// 이벤트 리스너 등록하기

class Toggle extends React.Component {
  constructor(props) {
    super(props);
    this.state = { isToggleOn: true };
  }

  handleClick(no) {
    console.log("===>", no);
    this.setState((prevState) => ({
      isToggleOn: !prevState.isToggleOn,
    }));
  }

  render() {
    let no = 100;

    // bind()를 이용하여 이벤트 핸들러에 값을 넘길 수 있다.
    return (
      <button onClick={this.handleClick.bind(this, no)}>
        {this.state.isToggleOn ? "ON" : "OFF"}
      </button>
    );
  }
}

const root = ReactDOM.createRoot(document.getElementById("root"));
root.render(<Toggle />);

 

 

resources\react\ex06

 

 

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>ex06</title>
  </head>
  <body>
    <h2>조건부 렌더링하기</h2>

    <div id="root"></div>

    <script
      src="https://unpkg.com/react@18/umd/react.development.js"
      crossorigin
    ></script>
    <script
      src="https://unpkg.com/react-dom@18/umd/react-dom.development.js"
      crossorigin
    ></script>
    <script src="https://unpkg.com/babel-standalone@6/babel.min.js"></script>

    <script src="test6.js"></script>
  </body>
</html>

 

 

조건부 렌더링하기
// ex06/src/test1.js
"use strict";

// 조건부 렌더링하기

function UserGreeting(props) {
  return <h1>Welcome back!</h1>;
}

function GuestGreeting(props) {
  return <h1>Please sign up.</h1>;
}

function Greeting(props) {
  const isLoggedIn = props.isLoggedIn;
  if (isLoggedIn) {
    return <UserGreeting />;
  }
  return <GuestGreeting />;
}

const root = ReactDOM.createRoot(document.getElementById("root"));
root.render(<Greeting isLoggedIn={true} />);

 

 

element를 변수에 담아 사용하기
// ex06/src/test2.js
"use strict";

// element를 변수에 담아 사용하기

function UserGreeting(props) {
  return <h1>Welcome back!</h1>;
}

function GuestGreeting(props) {
  return <h1>Please sign up.</h1>;
}

function Greeting(props) {
  const isLoggedIn = props.isLoggedIn;
  if (isLoggedIn) {
    return <UserGreeting />;
  }
  return <GuestGreeting />;
}

function LoginButton(props) {
  return <button onClick={props.onClick}>Login</button>;
}

function LogoutButton(props) {
  return <button onClick={props.onClick}>Logout</button>;
}

class LoginControl extends React.Component {
  constructor(props) {
    super(props);
    this.state = { isLoggedIn: false };
    this.handleLoginClick = this.handleLoginClick.bind(this);
    this.handleLogoutClick = this.handleLogoutClick.bind(this);
  }

  handleLoginClick() {
    this.setState({ isLoggedIn: true });
  }

  handleLogoutClick() {
    this.setState({ isLoggedIn: false });
  }

  render() {
    const isLoggedIn = this.state.isLoggedIn;
    let button;
    if (isLoggedIn) {
      button = <LogoutButton onClick={this.handleLogoutClick} />;
    } else {
      button = <LoginButton onClick={this.handleLoginClick} />;
    }

    // 다음과 같이 button 에 저장된 element를 삽입할 수 있다.
    return (
      <div>
        <Greeting isLoggedIn={isLoggedIn} />
        {button}
      </div>
    );
  }
}

const root = ReactDOM.createRoot(document.getElementById("root"));
root.render(<LoginControl />);

 

 

&& 연산자를 이용한 if를 JSX 안에 삽입하기
// ex06/src/test3.js
"use strict";

// && 연산자를 이용한 if를 JSX 안에 삽입하기

function Mailbox(props) {
  const unreadMessages = props.unreadMessages;
  return (
    <div>
      <h1>Hello!</h1>
      {unreadMessages.length > 0 && (
        <h2>You have {unreadMessages.length} unread messages.</h2>
      )}
    </div>
  );
}

const messages = ["React", "Re: React", "Re: Re: React"];

const root = ReactDOM.createRoot(document.getElementById("root"));
root.render(<Mailbox unreadMessages={messages} />);

 

 

? : 연산자 사용하기
// ex06/src/test4.js
"use strict";

// ? : 연산자 사용하기

function LoginStatus(props) {
  const isLoggedIn = props.isLoggedIn;
  return (
    <div>
      The user is <b>{isLoggedIn ? "currently" : "not"}</b> logged in.
    </div>
  );
}

const root = ReactDOM.createRoot(document.getElementById("root"));
root.render(<LoginStatus isLoggedIn={false} />);

 

 

? : 연산자 사용하기 II
// ex06/src/test5.js
"use strict";

// ? : 연산자 사용하기 II

function UserGreeting(props) {
  return <h1>Welcome back!</h1>;
}

function GuestGreeting(props) {
  return <h1>Please sign up.</h1>;
}

function Greeting(props) {
  const isLoggedIn = props.isLoggedIn;
  if (isLoggedIn) {
    return <UserGreeting />;
  }
  return <GuestGreeting />;
}

function LoginButton(props) {
  return <button onClick={props.onClick}>Login</button>;
}

function LogoutButton(props) {
  return <button onClick={props.onClick}>Logout</button>;
}

class LoginControl extends React.Component {
  constructor(props) {
    super(props);
    this.state = { isLoggedIn: false };
    this.handleLoginClick = this.handleLoginClick.bind(this);
    this.handleLogoutClick = this.handleLogoutClick.bind(this);
  }

  handleLoginClick() {
    this.setState({ isLoggedIn: true });
  }

  handleLogoutClick() {
    this.setState({ isLoggedIn: false });
  }

  render() {
    const isLoggedIn = this.state.isLoggedIn;
    return (
      <div>
        <Greeting isLoggedIn={isLoggedIn} />
        {isLoggedIn ? (
          <LogoutButton onClick={this.handleLogoutClick} />
        ) : (
          <LoginButton onClick={this.handleLoginClick} />
        )}
      </div>
    );
  }
}

const root = ReactDOM.createRoot(document.getElementById("root"));
root.render(<LoginControl />);

 

 

컴포너트가 렌더링 하는 것을 막기
// ex06/src/test6.js
"use strict";

// 컴포너트가 렌더링 하는 것을 막기
function WarningBanner(props) {
  if (!props.warn) {
    return null;
  }

  return <div className="warning">Warning!</div>;
}

class Page extends React.Component {
  constructor(props) {
    super(props);
    this.state = { showWarning: true };
    this.handleToggleClick = this.handleToggleClick.bind(this);
  }

  handleToggleClick() {
    this.setState((state) => ({
      showWarning: !state.showWarning,
    }));
  }

  render() {
    return (
      <div>
        <WarningBanner warn={this.state.showWarning} />
        <button onClick={this.handleToggleClick}>
          {this.state.showWarning ? "Hide" : "Show"}
        </button>
      </div>
    );
  }
}

const root = ReactDOM.createRoot(document.getElementById("root"));
root.render(<Page />);

 

 

resources\react\ex07

 

 

여러 개의 컴포넌트 렌더링하기
// ex07/src/test1.js
"use strict";

// 여러 개의 컴포넌트 렌더링하기

const numbers = [1, 2, 3, 4, 5];
const listItems = numbers.map((number) => <li>{number}</li>);

const root = ReactDOM.createRoot(document.getElementById("root"));
root.render(<ul>{listItems}</ul>);

 

 

여러 개의 컴포넌트 렌더링하기 - 함수 컴포넌트로 처리
// ex07/src/test2.js
"use strict";

// 여러 개의 컴포넌트 렌더링하기 - 함수 컴포넌트로 처리

function NumberList(props) {
  const numbers = props.numbers;
  const listItems = numbers.map((number) => <li>{number}</li>);
  return <ul>{listItems}</ul>;
}

const numbers = [1, 2, 3, 4, 5];
const root = ReactDOM.createRoot(document.getElementById("root"));
root.render(<NumberList numbers={numbers} />);

 

 

목록의 각 항목에 key 추가하기
// ex07/src/test3.js
"use strict";

// 목록의 각 항목에 key 추가하기

function NumberList(props) {
  const numbers = props.numbers;
  const listItems = numbers.map((number) => (
    <li key={number.toString()}>{number}</li>
  ));
  return <ul>{listItems}</ul>;
}

const numbers = [1, 2, 3, 4, 5];
const root = ReactDOM.createRoot(document.getElementById("root"));
root.render(<NumberList numbers={numbers} />);

 

 

key로 컴포넌트 추출하기
// ex07/src/test4.js
"use strict";

// key로 컴포넌트 추출하기

function ListItem(props) {
  return <li>{props.value}</li>;
}

function NumberList(props) {
  const numbers = props.numbers;
  const listItems = numbers.map((number) => (
    // key는 배열 안에 넣어야 한다.
    <ListItem key={number.toString()} value={number} />
  ));
  return <ul>{listItems}</ul>;
}

const numbers = [1, 2, 3, 4, 5];
const root = ReactDOM.createRoot(document.getElementById("root"));
root.render(<NumberList numbers={numbers} />);

 

 

key는 배열 안에서만 중복되지 않으면 된다.
// ex07/src/test5.js
"use strict";

// key는 배열 안에서만 중복되지 않으면 된다.
// 배열이 다르면 상관없다.

function Blog(props) {
  const sidebar = (
    <ul>
      {props.posts.map((post) => (
        <li key={post.id}>{post.title}</li>
      ))}
    </ul>
  );

  const content = props.posts.map((post) => (
    <div key={post.id}>
      <h3>{post.title}</h3>
      <p>{post.content}</p>
    </div>
  ));

  return (
    <div>
      {sidebar}
      <hr />
      {content}
    </div>
  );
}

const posts = [
  { id: 1, title: "Hello World", content: "Welcome to learning React!" },
  { id: 2, title: "Installation", content: "You can install React from npm." },
];

const root = ReactDOM.createRoot(document.getElementById("root"));
root.render(<Blog posts={posts} />);

 

 

JSX에 map() 포함시키기
// ex07/src/test6.js
"use strict";

// JSX에 map() 포함시키기

function ListItem(props) {
  return <li>{props.value}</li>;
}

function NumberList(props) {
  const numbers = props.numbers;
  return (
    <ul>
      {numbers.map((number) => (
        <ListItem key={number.toString()} value={number} />
      ))}
    </ul>
  );
}

const numbers = [1, 2, 3, 4, 5];
const root = ReactDOM.createRoot(document.getElementById("root"));
root.render(<NumberList numbers={numbers} />);

 

 

resources\react\ex08

 

 

<!-- ex08/index.html -->
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>ex08</title>
  </head>
  <body>
    <h2>폼</h2>

    <div id="root"></div>

    <script
      src="https://unpkg.com/react@18/umd/react.development.js"
      crossorigin
    ></script>
    <script
      src="https://unpkg.com/react-dom@18/umd/react-dom.development.js"
      crossorigin
    ></script>
    <script src="https://unpkg.com/babel-standalone@6/babel.min.js"></script>

    <script src="test8.js"></script>
  </body>
</html>

 

 

폼과 제어 컴포넌트(Controlled Component)
// ex08/src/test1.js
"use strict";

// 폼과 제어 컴포넌트(Controlled Component)

class NameForm extends React.Component {
  constructor(props) {
    super(props);
    this.state = { value: "" };
    this.handleChange = this.handleChange.bind(this);
    this.handleSubmit = this.handleSubmit.bind(this);
  }

  handleChange(event) {
    this.setState({ value: event.target.value });
  }

  handleSubmit(event) {
    alert("A name was submitted: " + this.state.value);
    event.preventDefault();
  }

  render() {
    return (
      <form onSubmit={this.handleSubmit}>
        <label>
          Name:
          <input
            type="text"
            value={this.state.value}
            onChange={this.handleChange}
          />
        </label>
        <input type="submit" value="Submit" />
      </form>
    );
  }
}

const root = ReactDOM.createRoot(document.getElementById("root"));
root.render(<NameForm />);

 

 

textarea 태그
// ex08/src/test2.js
"use strict";

// textarea 태그

class EssayForm extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      value: "Please write an essay about your favorite DOM element.",
    };
    this.handleChange = this.handleChange.bind(this);
    this.handleSubmit = this.handleSubmit.bind(this);
  }

  handleChange(event) {
    this.setState({ value: event.target.value });
  }

  handleSubmit(event) {
    alert("An essay was submitted: " + this.state.value);
    event.preventDefault();
  }

  render() {
    return (
      <form onSubmit={this.handleSubmit}>
        <label>
          Essay:
          <textarea value={this.state.value} onChange={this.handleChange} />
        </label>
        <input type="submit" value="Submit" />
      </form>
    );
  }
}

const root = ReactDOM.createRoot(document.getElementById("root"));
root.render(<EssayForm />);

 

 

select 태그
// ex08/src/test3.js
"use strict";

// select 태그

class FlavorForm extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      value: ["lime", "mango"],
    };
    this.handleChange = this.handleChange.bind(this);
    this.handleSubmit = this.handleSubmit.bind(this);
  }

  handleChange(event) {
    this.setState({ value: event.target.value });
  }

  handleSubmit(event) {
    alert("Your favorite flavor is: " + this.state.value);
    event.preventDefault();
  }

  render() {
    return (
      <form onSubmit={this.handleSubmit}>
        <label>
          Pick your favorite flavor:
          <select
            multiple={true}
            value={this.state.value}
            onChange={this.handleChange}
          >
            <option value="grapefruit">Grapefruit</option>
            <option value="lime">Lime</option>
            <option value="coconut">Coconut</option>
            <option value="mango">Mango</option>
          </select>
        </label>
        <input type="submit" value="Submit" />
      </form>
    );
  }
}

const root = ReactDOM.createRoot(document.getElementById("root"));
root.render(<FlavorForm />);

 

 

다중 입력 제어
// ex08/src/test4.js
"use strict";

// 다중 입력 제어

class Reservation extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      isGoing: true,
      numberOfGuests: 2,
    };
    this.handleInputChange = this.handleInputChange.bind(this);
  }

  handleInputChange(event) {
    const target = event.target;
    const value = target.type === "checkbox" ? target.checked : target.value;
    const name = target.name;

    // ES6의 computed property name 문법
    this.setState({ [name]: value });

    // ES5의 문법
    // let partialState = {};
    // partialState[name] = value;
    // this.setState(partialState);

    // setState()는 기존 state에 바뀐 부분만 병합한다.
    // 따라서 바뀐 부분만 설정하면 된다.
  }

  render() {
    return (
      <form onSubmit={this.handleSubmit}>
        <label>
          Is going:
          <input
            name="isGoing"
            type="checkbox"
            checked={this.state.isGoing}
            onChange={this.handleInputChange}
          />
        </label>
        <br />
        <label>
          Number of guests:
          <input
            name="numberOfGuests"
            type="number"
            value={this.state.numberOfGuests}
            onChange={this.handleInputChange}
          />
        </label>
      </form>
    );
  }
}

const root = ReactDOM.createRoot(document.getElementById("root"));
root.render(<Reservation />);

 

 

제어 컴포넌트의 value에 값을 지정할 때와 null을 지정할 때
// ex08/src/test5.js
"use strict";

// 제어 컴포넌트의 value에 값을 지정할 때와 null을 지정할 때
// => 값을 지정하면, 사용자가 변경할 수 없다.
// => null을 지정하면, 사용자가 변경할 수 있다.

const root = ReactDOM.createRoot(document.getElementById("root"));
root.render(<input value="hi" />);

setTimeout(function () {
  root.render(<input value={null} />);
}, 3000);

 

 

비제어 컴포넌트
// ex08/src/test6.js
"use strict";

// 비제어 컴포넌트
// => DOM 자체에서 폼 데이터를 다룬다.

class NameForm extends React.Component {
  constructor(props) {
    super(props);

    // 리액트컴포넌트에서 값을 다루지 않는다.
    // this.state = { value: "" };
    // this.handleChange = this.handleChange.bind(this);

    // DOM의 값을 직접 다룰 때 사용할 ref를 생성한다.
    this.input = React.createRef();

    this.handleSubmit = this.handleSubmit.bind(this);
  }

  // 리액트에서 폼 값을 다루지 않는다.
  // handleChange(event) {
  //   this.setState({ value: event.target.value });
  // }

  handleSubmit(event) {
    // alert("A name was submitted: " + this.state.value);

    // ref를 통해 직접 DOM의 값을 꺼낸다.
    alert("A name was submitted: " + this.input.current.value);
    event.preventDefault();
  }

  render() {
    return (
      <form onSubmit={this.handleSubmit}>
        <label>
          Name:
          <input
            type="text"
            // 리액트에서 값을 다루지 않는다.
            //value={this.state.value}
            //onChange={this.handleChange}

            // DOM의 값을 직접 다룰 수 있도록 ref와 연결한다.
            ref={this.input}
          />
        </label>
        <input type="submit" value="Submit" />
      </form>
    );
  }
}

const root = ReactDOM.createRoot(document.getElementById("root"));
root.render(<NameForm />);

 

 

비제어 컴포넌트의 기본 값
// ex08/src/test7.js
"use strict";

// 비제어 컴포넌트의 기본 값

class NameForm extends React.Component {
  constructor(props) {
    super(props);
    this.input = React.createRef();
    this.handleSubmit = this.handleSubmit.bind(this);
  }

  handleSubmit(event) {
    alert("A name was submitted: " + this.input.current.value);
    event.preventDefault();
  }

  render() {
    return (
      <form onSubmit={this.handleSubmit}>
        <label>
          Name:
          <input
            // 컴포넌트가 mount 된 다음에는
            // defaultValue 속성 값을 변경해도
            // DOM의 값이 변경되지 않는다.
            defaultValue="홍길동"
            type="text"
            ref={this.input}
          />
        </label>
        <input type="submit" value="Submit" />
      </form>
    );
  }
}

const root = ReactDOM.createRoot(document.getElementById("root"));
root.render(<NameForm />);

 

 

비제어 컴포넌트 - 파일 입력 태그
// ex08/src/test8.js
"use strict";

// 비제어 컴포넌트 - 파일 입력 태그
// => <input type="file" />은 항상 비제어 컴포넌트다.
// => 프로그래밍으로 값을 다룰 수 없다.
//

class FileInput extends React.Component {
  constructor(props) {
    super(props);
    this.fileInput = React.createRef();
    this.handleSubmit = this.handleSubmit.bind(this);
  }

  handleSubmit(event) {
    event.preventDefault();
    alert(`Selected file:  ${this.fileInput.current.files[0].name}`);
  }

  render() {
    return (
      <form onSubmit={this.handleSubmit}>
        <label>
          Upload file:
          <input type="file" ref={this.fileInput} />
        </label>
        <input type="submit" value="Submit" />
      </form>
    );
  }
}

const root = ReactDOM.createRoot(document.getElementById("root"));
root.render(<FileInput />);

 

 

resources\react\ex09

 

 

State 끌어 올리기 - 여러 컴포넌트에서 데이터를 공유하는 방법
1단계
// ex09/src/test1.js
"use strict";

// State 끌어 올리기 - 여러 컴포넌트에서 데이터를 공유하는 방법
// 1단계

function BoilingVerdict(props) {
  if (props.celsius >= 100) {
    return <p>The water would boil.</p>;
  }
  return <p>The water would not boil.</p>;
}

class Calculator extends React.Component {
  constructor(props) {
    super(props);
    this.state = { temperature: "" };
    this.handleChange = this.handleChange.bind(this);
  }

  handleChange(event) {
    this.setState({ temperature: event.target.value });
  }

  render() {
    const temperature = this.state.temperature;
    return (
      <fieldset>
        <legend>섭씨 온도:</legend>
        <input type="number" value={temperature} onChange={this.handleChange} />
        <BoilingVerdict celsius={parseFloat(temperature)} />
      </fieldset>
    );
  }
}

const root = ReactDOM.createRoot(document.getElementById("root"));
root.render(<Calculator />);

 

 

State 끌어 올리기 - 여러 컴포넌트에서 데이터를 공유하는 방법
2단계
// ex09/src/test2.js
"use strict";

// State 끌어 올리기 - 여러 컴포넌트에서 데이터를 공유하는 방법
// 2단계

function BoilingVerdict(props) {
  if (props.celsius >= 100) {
    return <p>The water would boil.</p>;
  }
  return <p>The water would not boil.</p>;
}

const scaleNames = {
  c: "Celsius",
  f: "Fahrenheit",
};

class TemperatureInput extends React.Component {
  constructor(props) {
    super(props);
    this.state = { temperature: "" };
    this.handleChange = this.handleChange.bind(this);
  }

  handleChange(e) {
    this.setState({ temperature: e.target.value });
  }

  render() {
    const temperature = this.state.temperature;
    const scale = this.props.scale;
    return (
      <fieldset>
        <legend>Enter temperature in {scaleNames[scale]}:</legend>
        <input value={temperature} onChange={this.handleChange} />
      </fieldset>
    );
  }
}

class Calculator extends React.Component {
  render() {
    return (
      <div>
        <TemperatureInput scale="c" />
        <TemperatureInput scale="f" />
      </div>
    );
  }
}

const root = ReactDOM.createRoot(document.getElementById("root"));
root.render(<Calculator />);

 

 

State 끌어 올리기 - 여러 컴포넌트에서 데이터를 공유하는 방법
3단계
// ex09/src/test3.js
"use strict";

// State 끌어 올리기 - 여러 컴포넌트에서 데이터를 공유하는 방법
// 3단계

function BoilingVerdict(props) {
  if (props.celsius >= 100) {
    return <p>The water would boil.</p>;
  }
  return <p>The water would not boil.</p>;
}

function toCelsius(fahrenheit) {
  return ((fahrenheit - 32) * 5) / 9;
}

function toFahrenheit(censius) {
  return (censius * 9) / 5 + 32;
}

function tryConvert(temperature, convert) {
  const input = parseFloat(temperature);
  if (Number.isNaN(input)) {
    return "";
  }
  const output = convert(input);
  const rounded = Math.round(output * 1000) / 1000;
  return rounded.toString();
}

const scaleNames = {
  c: "Celsius",
  f: "Fahrenheit",
};

class TemperatureInput extends React.Component {
  constructor(props) {
    super(props);
    this.handleChange = this.handleChange.bind(this);
  }

  handleChange(e) {
    this.props.onTemperatureChange(e.target.value);
  }

  render() {
    const temperature = this.props.temperature;
    const scale = this.props.scale;
    return (
      <fieldset>
        <legend>Enter temperature in {scaleNames[scale]}:</legend>
        <input value={temperature} onChange={this.handleChange} />
      </fieldset>
    );
  }
}

class Calculator extends React.Component {
  constructor(props) {
    super(props);
    this.handleCelsiusChange = this.handleCelsiusChange.bind(this);
    this.handleFahrenheitChange = this.handleFahrenheitChange.bind(this);
    this.state = { scale: "c", temperature: "" };
  }

  handleCelsiusChange(temperature) {
    this.setState({ scale: "c", temperature });
  }

  handleFahrenheitChange(temperature) {
    this.setState({ scale: "f", temperature });
  }

  render() {
    const scale = this.state.scale;
    const temperature = this.state.temperature;
    const celsius =
      scale === "f" ? tryConvert(temperature, toCelsius) : temperature;
    const fahrenheit =
      scale === "c" ? tryConvert(temperature, toFahrenheit) : temperature;

    return (
      <div>
        <TemperatureInput
          scale="c"
          temperature={celsius}
          onTemperatureChange={this.handleCelsiusChange}
        />
        <TemperatureInput
          scale="f"
          temperature={fahrenheit}
          onTemperatureChange={this.handleFahrenheitChange}
        />
        <BoilingVerdict celsius={parseFloat(celsius)} />
      </div>
    );
  }
}

const root = ReactDOM.createRoot(document.getElementById("root"));
root.render(<Calculator />);

 

 

resources\react\ex10

 

 

다른 컴포넌트 담기
<!-- ex10/test1.html -->
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>ex10</title>
    <style>
      .FancyBorder {
        padding: 10px 10px;
        border: 10px solid;
      }

      .FancyBorder-blue {
        border-color: blue;
      }

      .Dialog-title {
        margin: 0;
        font-family: sans-serif;
      }

      .Dialog-message {
        font-size: larger;
      }
    </style>
  </head>
  <body>
    <h2>합성과 상속</h2>

    <div id="root"></div>

    <script
      src="https://unpkg.com/react@18/umd/react.development.js"
      crossorigin
    ></script>
    <script
      src="https://unpkg.com/react-dom@18/umd/react-dom.development.js"
      crossorigin
    ></script>
    <script src="https://unpkg.com/babel-standalone@6/babel.min.js"></script>

    <script src="test1.js"></script>
  </body>
</html>

 

// ex10/test1.js
"use strict";

// 다른 컴포넌트 담기

function FancyBorder(props) {
  return (
    <div className={"FancyBorder FancyBorder-" + props.color}>
      {props.children}
    </div>
  );
}

function WelcomeDialog() {
  return (
    <FancyBorder color="blue">
      <h1 className="Dialog-title">Welcome</h1>
      <p className="Dialog-message">Thank you for visiting our spacecraft!</p>
    </FancyBorder>
  );
}

const root = ReactDOM.createRoot(document.getElementById("root"));
root.render(<WelcomeDialog />);

 

 

다른 컴포넌트 담기 - 화면 레이아웃에 활용
<!-- ex10/test2.html -->
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>ex10</title>
    <style>
      html,
      body,
      #root {
        width: 100%;
        height: 100%;
      }

      .SplitPane {
        width: 100%;
        height: 100%;
      }

      .SplitPane-left {
        float: left;
        width: 30%;
        height: 100%;
      }

      .SplitPane-right {
        float: left;
        width: 70%;
        height: 100%;
      }

      .Contacts {
        width: 100%;
        height: 100%;
        background: lightblue;
      }

      .Chat {
        width: 100%;
        height: 100%;
        background: pink;
      }
    </style>
  </head>
  <body>
    <h2>합성과 상속</h2>

    <div id="root"></div>

    <script
      src="https://unpkg.com/react@18/umd/react.development.js"
      crossorigin
    ></script>
    <script
      src="https://unpkg.com/react-dom@18/umd/react-dom.development.js"
      crossorigin
    ></script>
    <script src="https://unpkg.com/babel-standalone@6/babel.min.js"></script>

    <script src="test2.js"></script>
  </body>
</html>

 

// ex10/test2.js
"use strict";

// 다른 컴포넌트 담기 - 화면 레이아웃에 활용

function Contacts() {
  return <div className="Contacts" />;
}

function Chat() {
  return <div className="Chat" />;
}

function SplitPane(props) {
  return (
    <div className="SplitPane">
      <div className="SplitPane-left">{props.left}</div>
      <div className="SplitPane-right">{props.right}</div>
    </div>
  );
}

function App() {
  return <SplitPane left={<Contacts />} right={<Chat />} />;
}

const root = ReactDOM.createRoot(document.getElementById("root"));
root.render(<App />);

 

 

다른 컴포넌트 담기 - 특수화
<!-- ex10/test3.html -->
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>ex10</title>
    <style>
      .FancyBorder {
        padding: 10px 10px;
        border: 10px solid;
      }

      .FancyBorder-blue {
        border-color: blue;
      }

      .Dialog-title {
        margin: 0;
        font-family: sans-serif;
      }

      .Dialog-message {
        font-size: larger;
      }
    </style>
  </head>
  <body>
    <h2>합성과 상속</h2>

    <div id="root"></div>

    <script
      src="https://unpkg.com/react@18/umd/react.development.js"
      crossorigin
    ></script>
    <script
      src="https://unpkg.com/react-dom@18/umd/react-dom.development.js"
      crossorigin
    ></script>
    <script src="https://unpkg.com/babel-standalone@6/babel.min.js"></script>

    <script src="test3.js"></script>
  </body>
</html>

 

// ex10/test3.js
"use strict";

// 다른 컴포넌트 담기 - 특수화

function FancyBorder(props) {
  return (
    <div className={"FancyBorder FancyBorder-" + props.color}>
      {props.children}
    </div>
  );
}

function Dialog(props) {
  return (
    <FancyBorder color="blue">
      <h1 className="Dialog-title">{props.title}</h1>
      <p className="Dialog-message">{props.message}</p>
    </FancyBorder>
  );
}

function WelcomeDialog() {
  return (
    <Dialog title="Welcome" message="Thank you for visiting our spacecraft!" />
  );
}

const root = ReactDOM.createRoot(document.getElementById("root"));
root.render(<WelcomeDialog />);

 

 

다른 컴포넌트 담기 - 클래스 합성
<!-- ex10/test4.html -->
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>ex10</title>
    <style>
      .FancyBorder {
        padding: 10px 10px;
        border: 10px solid;
      }

      .FancyBorder-blue {
        border-color: blue;
      }

      .Dialog-title {
        margin: 0;
        font-family: sans-serif;
      }

      .Dialog-message {
        font-size: larger;
      }
    </style>
  </head>
  <body>
    <h2>합성과 상속</h2>

    <div id="root"></div>

    <script
      src="https://unpkg.com/react@18/umd/react.development.js"
      crossorigin
    ></script>
    <script
      src="https://unpkg.com/react-dom@18/umd/react-dom.development.js"
      crossorigin
    ></script>
    <script src="https://unpkg.com/babel-standalone@6/babel.min.js"></script>

    <script src="test4.js"></script>
  </body>
</html>

 

// ex10/test4.js
"use strict";

// 다른 컴포넌트 담기 - 클래스 합성
/*
튜토리얼 문서 중에서, 
"Facebook에서는 수천 개의 React 컴포넌트를 사용하지만, 
 컴포넌트를 상속 계층 구조로 작성을 권장할만한 사례를 
 아직 찾지 못했습니다.
 props와 합성은 명시적이고 안전한 방법으로 
 컴포넌트의 모양과 동작을 커스터마이징하는데 필요한 모든 
 유연성을 제공합니다. 
 컴포넌트가 원시 타입의 값, React 엘리먼트 혹은 함수 등 
 어떠한 props도 받을 수 있다는 것을 기억하세요."
*/

function FancyBorder(props) {
  return (
    <div className={"FancyBorder FancyBorder-" + props.color}>
      {props.children}
    </div>
  );
}

function Dialog(props) {
  return (
    <FancyBorder color="blue">
      <h1 className="Dialog-title">{props.title}</h1>
      <p className="Dialog-message">{props.message}</p>
      {props.children}
    </FancyBorder>
  );
}

class SignUpDialog extends React.Component {
  constructor(props) {
    super(props);
    this.handleChange = this.handleChange.bind(this);
    this.handleSignUp = this.handleSignUp.bind(this);
    this.state = { login: "" };
  }

  render() {
    return (
      <Dialog
        title="Mars Exploration Program"
        message="How should we refer to you?"
      >
        <input value={this.state.login} onChange={this.handleChange} />
        <button onClick={this.handleSignUp}>Sign Me Up!</button>
      </Dialog>
    );
  }

  handleChange(e) {
    this.setState({ login: e.target.value });
  }

  handleSignUp() {
    alert(`Welcome aboard, ${this.state.login}!`);
  }
}

const root = ReactDOM.createRoot(document.getElementById("root"));
root.render(<SignUpDialog />);