iT邦幫忙

2017 iT 邦幫忙鐵人賽
DAY 15
0
Modern Web

寫React的那些事系列 第 15

React Day15 - TODOS Demo(3)

  • 分享至 

  • xImage
  •  

今天要繼續補強我們Todo list的功能,還有add task跟delete task的功能尚未完成~~加油加油!

Step1


首先,我們先來做add task的功能

app.js

新增一個_addTask的function,並傳入一個參數接收要新增的task內容,如同之前edit提到的,我們需要用Spread Operator,先把array copy到另一個變數,再把我們新的task push進去,一定要避免直接修改到state。記得如果要在自己建立的_addTask使用this,要到constructor去bind指定喔!這邊就不再顯示code。

_addTask(val) {
  // 一樣不能直接修改state
  let newTodos = [...this.state.todos];
  newTodos.push(
    {
      task: val,
      isCompleted: false
    });
  this.setState({ todos: newTodos });
}

另外,在render時,要把_addTask傳給TodoAdd

<TodoAdd addTask={this._addTask} />

TodoAdd.js

  • 設定input的ref,讓save的時候可以找到input元件。
  • 設定Create button的onClick。
  • 新增_onAddClick,並且執行props傳來的addTask function,把修改的值傳入。
class TodoAdd extends Component {
  constructor(props) {
    super(props);
    this._onAddClick = this._onAddClick.bind(this);
  }

  render() {
    return (
      <div>
        <input type="text" ref="addInput" />
        <button onClick={this._onAddClick}>Create</button>
      </div>
    );
  }

  _onAddClick() {
    const addInput = this.refs.addInput;

    this.props.addTask(addInput.value);
    addInput.value = '';
  }
}

以上的步驟,我們就把新增的功能也完成了!是不是覺得React其實很容易上手,把元件切割好後,只要思考資料的處理部分,就會顯得容易很多。

Step2


再來就是delete的功能

app.js

從app.js開始先建立delete function,一樣記得要在constructor做bind。

_deleteTask(idx) {
  let newTodos = [...this.state.todos];
  newTodos.splice(idx, 1);
  this.setState({ todos: newTodos });
}

並且在render時,把delete function傳入,這邊因為一行寫完要傳給TodoList的props太多了,建議的寫法是如果傳超過一個props就可以每一個props換行,對齊排列,這樣比較能一目了然到底傳哪些props給子元件。

render() {
  return (
    <div>
      <h1>React Todo List</h1>
      <TodoAdd addTask={this._addTask} />
      <TodoList
        todos={this.state.todos}
        saveTask={this._saveTask}
        deleteTask={this._deleteTask}
      />
    </div>
  );
}

TodoList.js

這邊一樣只做拿props的deleteTask,傳給TodoItem。使用ES6 Destructuring assignment,我們把從props會拿到的todos, saveTask, deleteTask都列出來。

_renderItems() {
  const { todos, saveTask, deleteTask } = this.props;

  let list = [];
  todos.forEach((todo, idx) => {
    list.push(
      <TodoItem
        key={idx}
        idx={idx}
        todo={todo}
        saveTask={saveTask}
        deleteTask={deleteTask}
      />);
  });
  return list;
}

TodoItem.js

最後的動作很簡單,在Delete button指定props傳來的deleteTask,但我們不能寫:

<button onClick={deleteTask(idx)}>Delete</button>

這樣會直接在render到這段程式碼的時候執行,我們可以使用先前有提到的ES6 Arrow Function,當onClick發生時,才執行deleteTask(idx)。

<button onClick={() => deleteTask(idx)}>Delete</button>

render完整程式碼如下:

render() {
  const { todo, idx, deleteTask } = this.props;
  if (this.state.isEditing) {
    return (
      <tr>
        <td>
          <input 
            type="text" 
            data-idx={idx} 
            defaultValue={todo.task} 
            ref="editInput" 
          />
        </td>
        <td>
          <button onClick={this._onSaveClick}>Save</button>
          <button onClick={this._onCancelClick}>Cancel</button>
        </td>
      </tr>
    );
  }

  return (
    <tr>
      <td>{todo.task}</td>
      <td>
        <button onClick={this._onEditClick}>Edit</button>
        <button onClick={() => deleteTask(idx)}>Delete</button>
      </td>
    </tr>
  );
}

我們已經把CRUD的功能都完成囉!今天的檔案已經放在Here


上一篇
React Day14 - TODOS Demo(2)
下一篇
React Day16 - TODOS Demo(4)
系列文
寫React的那些事31
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言