關於 React 小書:做出 React


Posted by YongChenSu on 2020-12-09

做出 React 的程式碼

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>3. practive</title>
  <style media="screen">
    .like-btn { font-size: 50px; }
  </style>
</head>
<body>
  <div class='wrapper'></div>
  <script type="text/javascript">
    const createDOMFromString = (domString) => {
      const div = document.createElement('div')
      div.innerHTML = domString
      return div
    }

    class Component {
      constructor (props = {}) {
        this.props = props
      }

      // 改變狀態
      setState (state) {
        // 將舊 (dom element) 儲存為變數
        const oldEl = this.el
        // 更新 state
        this.state = state
        // 更新 dom element
        this.el = this.renderDOM()
        // 觸發 onstateChange 函式
        if (this.onStateChange) this.onStateChange(oldEl, this.el)
      }

      // 渲染畫面
      renderDOM () {
        // 將 string 變成 dom element
        this.el = createDOMFromString(this.render())
        // 若觸發 onClick 函式
        if (this.onClick) {
          // dom element 上觸發 click 事件,
          this.el.addEventListener('click', this.onClick.bind(this), false)
        }
        // 回傳觸發 click 事件後的 dom element
        return this.el
      }
    }

    // 將 dom element 用 mount 函式加到 container 上
    const mount = (component, wrapper) => {
      // 將渲染後且有觸發 click 事件的 dom 元素放到 wrapper 中
      wrapper.appendChild(component.renderDOM())
      // 在傳入的 component 加上 onStateChange 函式,依序傳入新舊兩個 dom element
      component.onStateChange = (oldEl, newEl) => {
        // 將新的 element 插在舊的 element 之前
        wrapper.insertBefore(newEl, oldEl)
        // 移除舊的 element
        wrapper.removeChild(oldEl)
      }
    }

    // 建立 LikeButton 類並繼承 Component
    class LikeButton extends Component {
      // 初始化並傳入 props
      constructor (props) {
        // 呼叫父類並將 props 傳上去
        super(props)
        // 初始化 this.state.isLiked 是 false
        this.state = { isLiked: false}
      }

      // onClick 函式
      onClick () {
        // 若觸發 onClick 函式則重新設置狀態
        this.setState({
          // 將 this.state.isLiked 的值設為相反
          isLiked: !this.state.isLiked
        })
      }

      // 渲染,回傳 string
      render() {
        return `
          <button class='like-btn' style="background-color: ${this.props.bgColor}">
            <span class='like-text'>
              ${this.state.isLiked ? '取消' : '點讚'}
            </span>
            <span>👍</span>
          </button>
        `
      }
    }

    // 選到帶有 wrapper css 屬性的 dom 元素
    const wrapper = document.querySelector('.wrapper')
    /* 
      建立新的 instance:LikeButton、傳入 props
      並利用 mount 函式將其放在 wrapper 中
    */
    mount(new LikeButton({ bgColor: 'red' }), wrapper)
    mount(new LikeButton(), wrapper)

  </script>
</body>
</html>


參考資源


#程式導師實驗計畫第四期 #前端 #React







Related Posts

AWS Solutions Architect - Associate (SAA) 學習計畫與備考心得: Module 9

AWS Solutions Architect - Associate (SAA) 學習計畫與備考心得: Module 9

關於 ASUS AiMesh 架設三兩句

關於 ASUS AiMesh 架設三兩句

CSS保健室|border-image-repeat

CSS保健室|border-image-repeat


Comments