欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

詳解React-Todos入門例子

 更新時間:2016年11月08日 12:13:08   作者:熱前端  
本篇文章主要介紹了React-Todos入門例子,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧

最近學(xué)完React的最基本概念,閑下來的時候就自己寫了一個Todo-List的小應(yīng)用。這里做個簡略的說明,給想好好學(xué)React的新手看。

開始之前

這里我用了webpackb做了babel和JSX預(yù)處理和模塊打包。所以對React和一些ES2015(ES6)的語法要有一定的了解。我相信學(xué)習(xí)ES2015絕對是劃算的,因?yàn)樗荍s的規(guī)范。這里給出學(xué)習(xí)的地方,阮一峰老師的ECMAScript 6 入門或者babel的相關(guān)文檔Learn ES2015。

最后的實(shí)際效果:

我們需要做到的功能有:

  1. 可以在最上面的input里,使用回車來添加任務(wù)。
  2. 在中間的任務(wù)列表里,由checkbox來控制任務(wù)的狀態(tài)。
  3. 已完成的任務(wù)有一個line-through的樣式。
  4. 當(dāng)鼠標(biāo)移到每一個任務(wù)時,都會出現(xiàn)刪除按鈕提供刪除。
  5. 在底部有一個全選按鈕,用于控制所有的任務(wù)狀態(tài)。
  6. 還有已完成與總數(shù)的顯示。
  7. 可以清空已完成的任務(wù)。

上面就是一個Todo-List最基本的功能,而我們這次就是用React實(shí)現(xiàn)上述功能。例子在我的github上可以download下來,可以用作參考:React-Todos

加載npm模塊

終于要開始我們的React-Todo的項(xiàng)目了,首先我們就要新建項(xiàng)目,通過npm我們可以很輕松的創(chuàng)建項(xiàng)目,并加載我們所需要的各個組件。大家可以在自己的項(xiàng)目里,用我的package.json去加載所需要的模塊。通過命令行進(jìn)行安裝。

$ npm install

這里提一下,因?yàn)槲覀冞@里僅僅是前端靜態(tài)的,并不涉及到數(shù)據(jù)庫。所以我自己寫了一個非常簡單的用于操作localStorage的小模塊localDb。所以涉及到數(shù)據(jù)存儲的時候,都是用localStorage來代替數(shù)據(jù)庫。它的原理就是,通過將數(shù)據(jù)格式化成JSON字符串進(jìn)行存儲,使用的時候就解析JSON字符串。這個模塊在我的github的例子里有,需要從那里復(fù)制一份來,放在node_modules的文件夾內(nèi)。

配置webpack

經(jīng)過一輪漫長的等待,我們終于安裝好所需要的各個模塊了。我們在開始我們的react的編碼前,需要對webpack進(jìn)行配置。關(guān)于webpack的學(xué)習(xí),我這里就不贅述了,在前一篇剛講完。下面直接看一看webpack.config.js。

// webpack.config.js
var path = require('path');

module.exports = {
  entry: "./src/entry.js",
  output: {
    path: path.join(__dirname, 'out'),
    publicPath: './out/',
    filename: "bundle.js"
  },
  externals: {
    'react': 'React'
  },
  module: {
    loaders: [
      { test: /\.js$/, loader: "jsx!babel", include: /src/},
      { test: /\.css$/, loader: "style!css"},
      { test: /\.scss$/, loader: "style!css!sass"},
      { test: /\.(jpg|png)$/, loader: "url?limit=8192"}
    ]
  }
};

這里一切從簡,可以看到入口文件是在src文件夾里的entry.js,然后輸出文件放在out文件夾的bundle.js里。

配置一下模塊的loaders,先用babel-loader再用jsx-loader。這樣子我們就可以讓ES6配合JSX編寫我們的React組件了。其它的加載器也沒什么好說的了,如果不清楚可以翻我上一篇關(guān)于webpack的文章。

這里提一下externals屬性,這個屬性是告訴webpack當(dāng)遇到require('react')的時候,不去處理并且默認(rèn)為全局的React變量。這樣子,我們就需要在index.html單獨(dú)用src去加載js。

分析各個組件

App組件

我這里并不會教大家手把手將這個React-Todo做出來,但是可以結(jié)合例子進(jìn)行分析理解。先來看看總的組件,也就是App。

import React from "react";
import LocalDb from "localDb";

import TodoHeader from "./TodoHeader.js";
import TodoMain from "./TodoMain.js";
import TodoFooter from "./TodoFooter.js";

class App extends React.Component {
  constructor(){
    super();
    this.db = new LocalDb('React-Todos');
    this.state = {
      todos: this.db.get("todos") || [],
      isAllChecked: false
    };
  }

  // 判斷是否所有任務(wù)的狀態(tài)都完成,同步底部的全選框
  allChecked(){
    let isAllChecked = false;
    if(this.state.todos.every((todo)=> todo.isDone)){
      isAllChecked = true;
    }
    this.setState({todos: this.state.todos, isAllChecked});
  }

  // 添加任務(wù),是傳遞給Header組件的方法
  addTodo(todoItem){
    this.state.todos.push(todoItem);
    this.allChecked();
    this.db.set('todos',this.state.todos);
  }

  // 改變?nèi)蝿?wù)狀態(tài),傳遞給TodoItem和Footer組件的方法
  changeTodoState(index, isDone, isChangeAll=false){
    if(isChangeAll){
      this.setState({
        todos: this.state.todos.map((todo) => {
          todo.isDone = isDone;
          return todo;
        }),
        isAllChecked: isDone
      })
    }else{
      this.state.todos[index].isDone = isDone;
      this.allChecked();
    }
    this.db.set('todos', this.state.todos);
  }

  // 清除已完成的任務(wù),傳遞給Footer組件的方法
  clearDone(){
    let todos = this.state.todos.filter(todo => !todo.isDone);
    this.setState({
      todos: todos,
      isAllChecked: false
    });
    this.db.set('todos', todos);
  }

  // 刪除當(dāng)前的任務(wù),傳遞給TodoItem的方法
  deleteTodo(index){
    this.state.todos.splice(index, 1);
    this.setState({todos: this.state.todos});
    this.db.set('todos', this.state.todos);
  }

  render(){
    var props = {
      todoCount: this.state.todos.length || 0,
      todoDoneCount: (this.state.todos && this.state.todos.filter((todo)=>todo.isDone)).length || 0
    };
    return (
      <div className="panel">
        <TodoHeader addTodo={this.addTodo.bind(this)}/>
        <TodoMain deleteTodo={this.deleteTodo.bind(this)} todos={this.state.todos} changeTodoState={this.changeTodoState.bind(this)}/>
        <TodoFooter isAllChecked={this.state.isAllChecked} clearDone={this.clearDone.bind(this)} {...props} changeTodoState={this.changeTodoState.bind(this)}/>
      </div>
    )
  }
}
React.render(<App/>, document.getElementById("app"));

用ES6寫React最大的不同就是,組件可以通過繼承React.Components來得到,并且初始化state也不需要冗長的getInitalialState,直接在構(gòu)造函數(shù)里操作this.state即可。更優(yōu)秀的便是...spread擴(kuò)展操作符,可以讓我們省下一堆不必要的代碼,這個接下來再說。

App狀態(tài)state

我們知道React的主流思想就是,所有的state狀態(tài)和方法都是由父組件控制,然后通過props傳遞給子組件,形成一個單方向的數(shù)據(jù)鏈路,保持各組件的狀態(tài)一致。所以我們在這個父組件App上,看的東西稍微有點(diǎn)多。一點(diǎn)點(diǎn)來看:

constructor(){
  super();
  this.db = new LocalDb('React-Todos');
  this.state = {
    todos: this.db.get("todos") || [],
    isAllChecked: false
  };
}

在App組件的constructor內(nèi),我們先是初始化了我們的localStorage的數(shù)據(jù)庫,放在了this.db上。然后便是初始化了state,分別有兩個,一個是todos的列表,一個是所有的todos是否全選的狀態(tài)。

App方法

// 判斷是否所有任務(wù)的狀態(tài)都完成,同步底部的全選框
allChecked()

// 添加一個任務(wù),參數(shù)是一個todoItem的object
addTodo(todoItem)

// 改變?nèi)蝿?wù)的狀態(tài),index是第幾個,isDone是狀態(tài),isChangeAll是控制全部狀態(tài)的
changeTodoState(index, isDone, isChangeAll=false) // 參數(shù)默認(rèn)位false

// 清空已完成
clearDone()

// 刪除面板上第幾個任務(wù)
deleteTodo(index)

// react用于渲染的函數(shù)
render(){
  <div className="panel">
    <TodoHeader />
    <TodoMain />
    <TodoFooter />
  </div>
}

我們可以從render函數(shù)看到整個組件的結(jié)構(gòu),可以看到其實(shí)結(jié)構(gòu)非常簡單,就是上中下。上面的TodoHeader自然就是用來輸入任務(wù)的地方,中間就是展示并操作todo-list的,而底部就是顯示數(shù)據(jù)并提供特殊操作。這里還是要提醒一句,所有標(biāo)簽都必須閉合,即使是非結(jié)對的,也要用斜杠閉合上。

  render(){
    var props = {
      todoCount: this.state.todos.length || 0,
      todoDoneCount: (this.state.todos && this.state.todos.filter((todo)=>todo.isDone)).length || 0
    };
    return (
      <div className="panel">
        <TodoHeader addTodo={this.addTodo.bind(this)}/>
        <TodoMain deleteTodo={this.deleteTodo.bind(this)} todos={this.state.todos} changeTodoState={this.changeTodoState.bind(this)}/>
        <TodoFooter isAllChecked={this.state.isAllChecked} clearDone={this.clearDone.bind(this)} {...props} changeTodoState={this.changeTodoState.bind(this)}/>
      </div>
    )
  }

我們可以看到,其他的方法都是傳到子組件上,就不一一詳細(xì)說如何實(shí)現(xiàn)的了。總體的思想就是,方法在父組件定義,通過props傳給需要的子組件進(jìn)行調(diào)用傳參,最后返回到父組件上執(zhí)行函數(shù),存儲數(shù)據(jù)、改變state和重新render。方法需要bind(this),不然方法內(nèi)部的this指向會不正確。

計算需要的數(shù)據(jù)后,通過props傳遞到子組件。如果細(xì)心的同學(xué)應(yīng)該可以看到像這樣的{...props},這就是我之前說過的spread操作符。如果我們沒有用這個操作符,就要這樣寫:

<TodoFooter {...props} /> // spread操作符
<TodoFooter todoCount={props.todoCount} todoDoneCount={props.todoDoneCount} />

最佳的實(shí)踐就是,當(dāng)父組件傳props給子組件,然后子組件要將props轉(zhuǎn)發(fā)給孫子組件的時候,spread操作符簡直讓人愉悅!可以對一堆麻煩又丑又長的代碼可以say goodbye了!

最后我們將整個App渲染到DOM上即可。

React.render(<App/>, document.getElementById("app"));

AppHeader組件

import React from "react";

class TodoHeader extends React.Component {

  // 綁定鍵盤回車事件,添加新任務(wù)
  handlerKeyUp(event){
    if(event.keyCode === 13){
      let value = event.target.value;

      if(!value) return false;

      let newTodoItem = {
        text: value,
        isDone: false
      };
      event.target.value = "";
      this.props.addTodo(newTodoItem);
    }
  }

  render(){
    return (
      <div className="panel-header">
        <input onKeyUp={this.handlerKeyUp.bind(this)} type="text" placeholder="what's your task ?"/>
      </div>
    )
  }
}

export default TodoHeader;

到了子組件,方法就沒那么多了,一般子組件就是綁定事件??梢钥吹皆谧咏M件綁定了keyUp事件,用來確定回車鍵并調(diào)用父組件傳來的addTodo(),將新生成的todo任務(wù)作為參數(shù)傳入。

AppFooter組件

import React from "react";
export default class TodoFooter extends React.Component{

  // 處理全選與全不選的狀態(tài)
  handlerAllState(event){
    this.props.changeTodoState(null, event.target.checked, true);
  }

  // 綁定點(diǎn)擊事件,清除已完成
  handlerClick(){
    this.props.clearDone();
  }

  render(){
    return (
      <div className="clearfix todo-footer">
        <input checked={this.props.isAllChecked} onChange={this.handlerAllState.bind(this)} type="checkbox" className="fl"/>
        <span className="fl">{this.props.todoDoneCount}已完成 / {this.props.todoCount}總數(shù)</span>
        <button onClick={this.handlerClick.bind(this)} className="fr">清除已完成</button>
      </div>
    )
  }
}

我們先來看看這個footer上有哪些方法。第一個就是處理todo狀態(tài)的,它通過底部的checkbox的change事件觸發(fā)。然后就是清空已完成的按鈕的點(diǎn)擊事件的方法handlerClick()。然后下面的數(shù)據(jù)顯示,就通過props的值進(jìn)行顯示。

TodoMain

import React from "react";
import TodoItem from "./TodoItem.js"

export default class TodoMain extends React.Component{
  // 遍歷顯示任務(wù),轉(zhuǎn)發(fā)props
  render(){
    return (
      <ul className="todo-list">
        {this.props.todos.map((todo, index) => {
          return <TodoItem key={index} {...todo} index={index} {...this.props}/>
        })}
      </ul>
    )
  }
}

Main組件的作用就是,將props傳過來的todos遍歷顯示出來。所以對每一個todo的細(xì)致操作都是放在TodoItem上。

TodoItem

import React from "react";
export default class TodoItem extends React.Component{

  // 處理任務(wù)是否完成狀態(tài)
  handlerChange(){
    let isDone = !this.props.isDone;
    this.props.changeTodoState(this.props.index, isDone);
  }

  // 鼠標(biāo)移入
  handlerMouseOver(){
    React.findDOMNode(this.refs.deleteBtn).style.display = "inline";
  }

  // 鼠標(biāo)移出
  handlerMouseOut(){
    React.findDOMNode(this.refs.deleteBtn).style.display = "none";
  }

  // 刪除當(dāng)前任務(wù)
  handlerDelete(){
    this.props.deleteTodo(this.props.index);
  }

  render(){
    let doneStyle = this.props.isDone ? {textDecoration: 'line-through'} : {textDecoration: 'none'};

    return (
      <li
        onMouseOver={this.handlerMouseOver.bind(this)}
        onMouseOut={this.handlerMouseOut.bind(this)}
      >
        <input type="checkbox" checked={this.props.isDone} onChange={this.handlerChange.bind(this)}/>
        <span style={doneStyle}>{this.props.text}</span>
        <button style={{'display': 'none'}} ref="deleteBtn" onClick={this.handlerDelete.bind(this)} className="fr">刪除</button>
      </li>
    )
  }
}

在TodoItem主要處理多個交互,包括修改任務(wù)狀態(tài),刪除任務(wù)。還有就是鼠標(biāo)移到相應(yīng)的任務(wù)上才顯示刪除按鈕。

我們可以看到render()函數(shù),是控制了任務(wù)的樣式。標(biāo)簽內(nèi)的style是需要接受一個對象的,所以所有的CSS屬性名,都要變成駝峰形的。

總結(jié)

其實(shí)真正的回過頭看React-Todos,會覺得React帶給我們的組件化的思想用起來太舒服了。我們通過父組件來控制狀態(tài),并通過props傳遞,來保證組件內(nèi)的狀態(tài)一致。我們可以非常有效的維護(hù)我們的交互代碼,因?yàn)槲覀円谎劬椭?,這個事件屬于哪個組件管理。它的模型其實(shí)非常輕,只有View層,但是它帶給我們?nèi)碌臅鴮懬岸私M件的方法是非常好的,我個人認(rèn)為如果未來的站點(diǎn)交互性愈來愈多,React是很有可能代替jQuery成為必備的技能。

以上就是本文的全部內(nèi)容,希望對大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。

相關(guān)文章

  • React路由管理之React Router總結(jié)

    React路由管理之React Router總結(jié)

    React項(xiàng)目通常都有很多的URL需要管理,最常使用的解決方案就是React Router了,本篇文章主要介紹了React路由管理之React Router總結(jié),小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2018-05-05
  • React.js入門實(shí)例教程之創(chuàng)建hello world 的5種方式

    React.js入門實(shí)例教程之創(chuàng)建hello world 的5種方式

    React 是近期非常熱門的一個前端開發(fā)框架。應(yīng)用非常廣泛,接下來通過本文給大家介紹React.js入門實(shí)例教程之創(chuàng)建hello world 的5種方式 ,需要的朋友參考下吧
    2016-05-05
  • react組件基本用法示例小結(jié)

    react組件基本用法示例小結(jié)

    這篇文章主要介紹了react組件基本用法,結(jié)合實(shí)例形式分析了react組件傳值、生命周期、受控組件和非受控組件等相關(guān)操作技巧,需要的朋友可以參考下
    2020-04-04
  • npx create-react-app xxx創(chuàng)建項(xiàng)目報錯的解決辦法

    npx create-react-app xxx創(chuàng)建項(xiàng)目報錯的解決辦法

    這篇文章主要介紹了npx create-react-app xxx創(chuàng)建項(xiàng)目報錯的解決辦法,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2020-02-02
  • React中setState的使用與同步異步的使用

    React中setState的使用與同步異步的使用

    這篇文章主要介紹了React中setState的使用與同步異步的使用,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2021-03-03
  • React類組件和函數(shù)組件對比-Hooks的簡介

    React類組件和函數(shù)組件對比-Hooks的簡介

    Hook?是?React?16.8?的新增特性,它可以讓我們在不編寫class的情況下,?使用state以及其他的React特性(比如生命周期,這篇文章主要介紹了React類組件和函數(shù)組件對比-Hooks的介紹及初體驗(yàn),需要的朋友可以參考下
    2022-11-11
  • React事件處理和表單的綁定詳解

    React事件處理和表單的綁定詳解

    這篇文章主要介紹了React事件處理和表單的綁定,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2022-08-08
  • React開發(fā)進(jìn)階redux saga使用原理詳解

    React開發(fā)進(jìn)階redux saga使用原理詳解

    這篇文章主要為大家介紹了React開發(fā)進(jìn)階redux saga使用原理詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2022-11-11
  • react中路由跳轉(zhuǎn)及傳參的實(shí)現(xiàn)

    react中路由跳轉(zhuǎn)及傳參的實(shí)現(xiàn)

    本文主要介紹了react中路由跳轉(zhuǎn)及傳參的實(shí)現(xiàn),文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2023-05-05
  • React大屏可視化腳手架教程示例

    React大屏可視化腳手架教程示例

    這篇文章主要為大家介紹了React大屏可視化腳手架教程示例,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2022-06-06

最新評論