最近在學 React.js,也寫了一些練習的項目,之前參考網上的一些代碼寫了一個很簡單的 to-do list。對於初學者來說,寫個基本的 to-do list 對於理解 React 中的一些概念及語法倒是挺有幫助的。
現在很多的 React 項目中已經開始使用 ES6 來寫了,不過因爲我在學習 React 的時候看的教程大多都是用 ES5 寫的,我這裏還是用的還是更熟悉的 ES5 寫法,雖然有點落伍了,但若想改成 ES6 版本倒也挺方便的。
文件目錄
在正式的生產項目中,使用 webpack 可以很方便地對我們的文件進行打包,這裏因爲程序比較簡單,直接用 <script>
標籤將 React
組件引入了。
首先新建一個 index.html
文件,引入相關的資源文件。
再新建一個 js
文件夾,我們使用 React 需要這樣的兩個文件: react.js
和 react-dom.js
,你可以使用
cdn 引入,這裏直接將文件下載放在了 js
文件夾內。
js
文件夾內還有一個 script.jsx
文件,我們程序的主要內容就放在這個文件中。注意這裏的後綴名是 jsx
,表示它是使用
React 的 jsx
語法來寫的,引入它的時候按如下寫法:
<script type="text/babel" src="js/script.jsx"></script>
同時還需要一個 browser.js
文件,它可以讓 jsx
語法的文件在瀏覽器中運行。
最後我們再建立一個 css
文件夾,存放樣式文件,我的項目中使用了 Bootstrap 的樣式,所以需要下載 Bootstrap 的樣式文件。
程序功能
作爲一個最簡單的 to-do list,這個程序沒有過多的功能。可以從 demo 裏看出,它的功能如下:
-
顯示每一個任務
-
可以將任務標記爲已完成,以區分未完成的任務
-
加入任務 / 刪除任務
-
統計任務總數和完成的任務數量
作爲一個示例程序,以上就是它的功能了。
組件結構
我們可以使用 React 開發出各種組件(component),利用不同組件的功能來實現一個應用。我們這裏創建的組件有:
TodoBox
-TodoList
-TodoItem
-TodoFooter
-TodoForm
-
TodoBox 是最外層的組件,其餘的都是它的子組件
-
TodoList 是各個單獨的待辦任務的集合
-
TodoItem 即爲一條單獨的待辦事項
-
TodoFooter 對上述的事項進行統計
-
TodoForm 用於加入新的項目
屬性的傳遞
React 的組件有兩種不同的屬性,state
和 props
。可以用一種簡單的方法來區分它們:如果這個屬性是其父組件傳給它的,那麼就是 props
,反之如果一個屬性是組件自己的,那麼就是 state
。
具體什麼時候用 state
,什麼時候用 props
,可以參考這幾條:
Is it passed in from a parent via props? If so, it probably isn't state.
Does it change over time? If not, it probably isn't state.
Can you compute it based on any other state or props in your component? If so, it's not state.
這裏我們從代碼來看看,屬性是如何從父組件傳遞到子組件的。
每一條待辦事項有這樣的幾個屬性:
-
id: 任務的編號
-
task: 任務的具體內容
-
complete: 任務是否已經完成
我們看看屬性的傳遞過程。
首先在 TodoBox
組件的 state
中有一個 data
對象:
data: [
{"id": "0001", "task":"吃飯", "complete": "false"},
{"id": "0002", "task":"睡覺", "complete": "true"},
...
]
TodoBox
組件的 render 函數中會有 TodoList
組件:
<TodoList data={this.state.data}
// 其他的屬性及方法寫在這裏
/>
這樣 TodoBox
組件的 data
屬性就傳遞給了子組件 TodoBox
。在 TodoBox
中通過 this.props
來引用這一屬性,即this.props.data
。
TodoBox
組件還有子組件 TodoItem
,可以將屬性繼續傳遞下去。在 TodoList
組件的 render
函數中這樣寫:
var taskList = this.props.data.map(function(listItem) {
return (
<TodoItem
taskId={listItem.id}
key={listItem.id}
task={listItem.task}
complete={listItem.complete}
// 其他的屬性及方法
)
}, this);
在 TodoItem
組件中就可以用 this.props.taskId
獲得任務的
id 了。
函數的傳遞
我們的程序中需要的函數有這幾個:
-
handleTaskDelete: 根據id刪除一項任務
-
handleToggleComplete: 切換一項任務的完成狀態
-
handleSubmit: 新增一項任務
-
generateId: 給新增的任務一個隨機的id
在 React 的組件中傳遞方法與傳遞屬性類似,現在 TodoBox
組件中有一個 handleToggleComplete
函數,將它傳遞給 TodoList
組件:
<TodoList toggleComplete={this.handleToggleComplete}
// 其他的屬性及方法寫在這裏
/>
這樣你就可以在 TodoList
組件中通過 this.props.toggleComplete
來調用這一方法了,你也可以將這一方法繼續向下一層的組件傳遞。
程序的運行
你可以下載 GitHub 上的項目文件,再用 python 開啓一個 HTTP 服務器,就可以打開 http://localhost:8000/ 查看運行結果了。
git clone https://github.com/noiron/simplest-react-todolist.git
cd simplest-react-todolist
python -m SimpleHTTP server // open a server with python
這篇博客裏沒有對整個項目所有的代碼進行分析,更多內容還是直接看代碼更清楚。
博客原地址:http://www.wukai.me/2016/06/19/write-a-simplest-todolist-with-reactjs/