今天要繼續補強我們Todo list的功能,還有add task跟delete task的功能尚未完成~~加油加油!
首先,我們先來做add task的功能
新增一個_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} />
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其實很容易上手,把元件切割好後,只要思考資料的處理部分,就會顯得容易很多。
再來就是delete的功能
從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>
);
}
這邊一樣只做拿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;
}
最後的動作很簡單,在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。