最近有個功能需要前端的畫面,功能不複雜而且是給內部使用,趁這個機會玩一下React讓腦袋有不同的刺激。
同事丟給我教學影片,由實作一個可新增/刪除的todo list app開始,範例的程式碼在這裡。
產生 React App
首先,使用create-react-app 這個npm module幫忙生成app的骨架
1 2 3 4 5 6
| npm install -g create-react-app
create-react-app todo-list
cd todo-list npm start
|
在瀏覽器輸入 http://localhost:3000/ 即可看到 app 的畫面
解析程式碼
App.js1 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 31 32
| import React, { Component } from 'react'; import './App.css'; import Header from './components/header';
class App extends Component { constructor(props) { super(props);
this.addTodo = this.addTodo.bind(this); this.removeTodo = this.removeTodo.bind(this); } addTodo(todoText) { console.log(`Add ${todoText}`); }
removeTodo(id) { console.log(`Removing ${id}`); } render() { return ( <div className="App"> <div className="todo-wrapper"> <Header /> </div> </div> ); } }
export default App;
|
1~3行將需要的module和css檔案載入專案
Class App 繼承React.Component, 所以在constructor裡需要先呼叫super才能使用父類別的成員函式 super的說明
接下來需要綁定 addTodo 和 removeTodo這二個成員函式讓之後的操作能正確使用bind的說明 Autobinding
render function將我們想呈現的畫面渲染出來,這也是React.Component中必需要實作的函式。其中,Header放在另一個js檔案裡
header.js1 2 3 4 5 6 7 8 9
| import React from 'react';
export default class Header extends React.Component { render() { return ( <h1>React Todo</h1> ); } }
|
JSX
看到這裡,相信有學過rails的人一定會對React的邏輯感覺到有所不同
在rails的view裡,前端基本上還是HTML的架構為主;而React則是以js搭配JSX操作component以呈現畫面
todoItem.js1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| import React from 'react'; import './todoItem.css';
export default class TodoItem extends React.Component { removeTodo(_id) { this.props.removeTodo(_id); }
render() { return ( <div className="todoWrapper"> <button className="removeTodo" onClick={(e) => this.removeTodo(this.props.id)}>remove</button>{this.props.todo.text} </div> ); } }
|
上述程式碼用來處理todo list的各個事項。在render裡可以看到HTML的class被換成className,這是為了和javascript的class做區別
而button的部分,在onClick事件觸發時會執行{(e) => this.removeTodo(this.props.id)}
,
這是javascript的語法,表示當button被點擊時會呼叫removeTodo,傳入待辦事項的id以移除。在removeTodo function裡又呼叫了this.props.removeTodo(_id)
,props是用來當作傳入component的參數,也就是說這裡將_id傳入App.js的removeTodo裡
App.js1 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 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48
| import React, { Component } from 'react'; import './App.css'; import Header from './components/header'; import TodoInput from './components/todoInput'; import TodoItem from './components/todoItem';
class App extends Component {
addTodo(todoText) { let todos = this.state.todos.slice(); todos.push({ _id: this.state.nextId, text: todoText }); const nextId = this.state.nextId + 1; this.setState({ todos, nextId }); }
removeTodo(id) { this.setState({ todos: this.state.todos.filter(todo => todo._id !== id), }); }
render() { return ( <div className="App"> <div className="todo-wrapper"> <Header /> <TodoInput todoText="" addTodo={this.addTodo}/> <ul> { this.state.todos.map((todo) => { return <TodoItem todo={todo} key={todo._id} id={todo._id} removeTodo={this.removeTodo}/> }) } </ul> </div> </div> ); } }
export default App;
|
以上就是React的初次介紹,其實學新東西最主要的目的不是為了跟上潮流,而是讓自己的腦袋活化,把其它知識做比較和整理並擴展認知邊界。
參考資料: