用 React.js 寫一個最簡單的 To-do List 應用

最近在學 React.js,也寫了一些練習的項目,之前參考網上的一些代碼寫了一個很簡單的 to-do list。對於初學者來說,寫個基本的 to-do list 對於理解 React 中的一些概念及語法倒是挺有幫助的。

現在很多的 React 項目中已經開始使用 ES6 來寫了,不過因爲我在學習 React 的時候看的教程大多都是用 ES5 寫的,我這裏還是用的還是更熟悉的 ES5 寫法,雖然有點落伍了,但若想改成 ES6 版本倒也挺方便的。

GitHub 上的項目地址
在線 demo

文件目錄

在正式的生產項目中,使用 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.

參考來源:Thinking in React

這裏我們從代碼來看看,屬性是如何從父組件傳遞到子組件的。

每一條待辦事項有這樣的幾個屬性:

  • 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/

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章