Lidemy / mentor-program-2nd-futianshen

mentor-program-2nd-futianshen created by GitHub Classroom
14 stars 2 forks source link

基礎 Todo List #46

Open futianshen opened 5 years ago

futianshen commented 5 years ago

功能:新增、刪除清單內容 網址連結:待補

index.js

import React from 'react'
import ReactDOM from 'react-dom'
import Todo from './Todo' 

class App extends React.Component { 
  constructor (props) {
    super(props) 
    this.state = { 
      value: '',
      todos: [],
      id: 0
    }
    this.handleClick = this.handleClick.bind(this)  // [1-2]
    this.handleChange = this.handleChange.bind(this)
    this.removeTodo = this.removeTodo.bind(this) 
    this.id = 0 
  }

  handleClick () {
    console.log(this) // [1-1]
    const { todos, value } = this.state
    this.setState({ 
      todos: [
        ...todos, 
        { 
          text: value,
          id: this.id++
        }
      ],
      value: ''
    })
  }

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

  removeTodo (todo) {
    const { todos } = this.state
    this.setState({
      todos: todos.filter(item => item.id !== todo.id )
    })
  }
  render () {
    console.log('App Render!')
    const { todos, value } = this.state
    return (
      <div>
        <h1>Todo list React Version</h1>
        <label>todo: 
          <input value={value} onChange={this.handleChange} />
        </label>
        <button onClick={this.handleClick}>Add Todo</button> 
        <ul className="todolist">
          {todos.map(todo => <Todo 
            key={todo.id} 
            todo={todo} 
            removeTodo={this.removeTodo} 
          />)} 
        </ul>
      </div>
    )
  }
} 

ReactDOM.render(
  <App />, 
  document.getElementById('root')
)

Todo.js

import React from 'react'

class Todo extends React.Component {
  constructor(props) {
    super(props)
    this.handleDelete = this.handleDelete.bind(this)
  }
  shouldComponentUpdate(nextProps) {
    if(nextProps.todo===this.props.todo) return false
    else return true
  }
  handleDelete() {
    const { todo, removeTodo } = this.props
    removeTodo(todo)
  }
  render () {
    console.log('Todo Render')
    const { todo } = this.props
    return (
     <li>{todo.id}: {todo.text}
      <button onClick={this.handleDelete}>X</button>
    </li>
    )
  }
}

export default Todo
futianshen commented 5 years ago

[1] this 的指向 (理解錯誤需要修改)

一旦你瞭解物件你就可以瞭解 JavaScript,JavaScript 中幾乎所有事物都是一種「物件」,或具有類似物件的行為。[a]

this 指向調用 this 的物件 [b]

所有函式都由一個「物件」呼叫,換句話說所有函式都是物件中的一個「方法」(method) [c]

[1-1] handleClick 由 windows 物件(Global Object)呼叫, this 指向 windows 物件,但由於 babel 預設開啟 Strict Mode 所以變成 undefined

[1-2] 我們希望呼叫 handleClick 這個 method 的時候,this 的指向是 App 這個 Component 的Instance,但我們自訂的method handleClick() 指向的是 Global Object 所以我們我們利用 this.handleClick = this.handleClick.bind(this)

參考資料

[a]《JavaScript深入精要》p.1 [b]《從 ES6 開始的 JavaScript 學習生活》 this - this [c]《從 ES6 開始的 JavaScript 學習生活》 this - 深入 函式 中