国产xxxx99真实实拍_久久不雅视频_高清韩国a级特黄毛片_嗯老师别我我受不了了小说

資訊專(zhuān)欄INFORMATION COLUMN

React, Redux的入門(mén)程序 - Todos

qqlcbb / 2562人閱讀

摘要:發(fā)現(xiàn)最近看到的框架入門(mén)程序都變成,我花了三個(gè)小時(shí)才自己實(shí)現(xiàn)了一個(gè)感嘆前端入門(mén)越來(lái)越復(fù)雜了,懷念幾年前還是的時(shí)代。。。主要負(fù)責(zé)的渲染,和那個(gè)框的功能。利用對(duì)的值進(jìn)行控制,然后監(jiān)聽(tīng)鍵盤(pán)來(lái)判斷是輸入還是提交。需要講解的不多。。。

發(fā)現(xiàn)最近看到的框架入門(mén)程序都變成Todos,我花了三個(gè)小時(shí)才自己實(shí)現(xiàn)了一個(gè)Todos...感嘆前端入門(mén)越來(lái)越復(fù)雜了,懷念幾年前還是hello world的時(shí)代。。。

吐槽不多說(shuō),這里主要說(shuō)的只是ReactRedux這一塊兒,css樣式完全是從這里抄過(guò)來(lái)的。

代碼的結(jié)構(gòu)準(zhǔn)備是這個(gè)樣子的:

轉(zhuǎn)化成代碼結(jié)構(gòu),就是這個(gè)樣子:

另外,按照官方示例,在Header左邊的toggleAll按鈕放到了Section中。

Redux Types/todos.js

Redux中,type是用于actionreducer交流的時(shí)候的一個(gè)flag,讓reducer知道這是一個(gè)什么請(qǐng)求。

我比較習(xí)慣把type多帶帶分離出來(lái),列到一個(gè)文件里面,讓Redux的文件更干凈,并便于管理。

/** ------------------------- TODO ---------------------*/
export const TODO_INSERT_ITEM = "TODO_INSERT_ITEM";
export const TODO_DELETE_ITEM = "TODO_DELETE_ITEM";
export const TODO_SWITCH_FILTER = "TODO_SWITCH_FILTER";
export const TODO_TOGGLE_ACTIVE = "TODO_TOGGLE_ACTIVE";
export const TODO_TOGGLE_ALL = "TODO_TOGGLE_ALL";
export const TODO_CHANGE_VALUE = "TODO_CHANGE_VALUE";
export const TODO_CLEAR_COMPLETED = "TODO_CLEAR_COMPLETED";
Actions/todos.js

根據(jù)上面列出的type,列出對(duì)應(yīng)的action creator

import { TODO_INSERT_ITEM, TODO_DELETE_ITEM, TODO_SWITCH_FILTER, TODO_TOGGLE_ACTIVE, TODO_TOGGLE_ALL, TODO_CHANGE_VALUE, TODO_CLEAR_COMPLETED } from "../types";

// 插入一個(gè)TODO 
export function insertItem(value){
  return {
    type: TODO_INSERT_ITEM,
    value
  };
}

// 刪除一個(gè)TODO
export function deleteItem(id) {
  return {
    type: TODO_DELETE_ITEM,
    id
  }
}

// 轉(zhuǎn)換一個(gè)TODO的狀態(tài)
export function switchFilter(filter) {
  return {
    type: TODO_SWITCH_FILTER,
    filter
  }
}

// 清楚所有完成的TODO
export function clearCompleted(){
  return {
    type: TODO_CLEAR_COMPLETED
  }
}

export function toggleActive(id){
  return {
    type: TODO_TOGGLE_ACTIVE,
    id
  }
}

// 轉(zhuǎn)換所有的狀態(tài)到active
export function toggleAll(active){
  return {
    type: TODO_TOGGLE_ALL,
    active
  }  
}

// 改變對(duì)應(yīng)TODO的值
export function changeValue(id, value) {
  return {
    type: TODO_CHANGE_VALUE,
    id,
    value
  }
}
Reducers/todos.js

reducer中需要注意幾點(diǎn):

初始化的state要從localStorage中獲取

每次做出修改,都要重新更新localStorage

數(shù)據(jù)沒(méi)有發(fā)生改變的時(shí)候,盡量使用原數(shù)據(jù),減少re-render

為了便于查找,我在這里用了lodashuniqueId方法,給每一個(gè)item加一個(gè)id

為了便于儲(chǔ)存和展示,我這里包含一個(gè)items用來(lái)保存所有的items,一個(gè)showedItems用來(lái)儲(chǔ)存需要展示的items

先提供一個(gè)簡(jiǎn)單的簡(jiǎn)寫(xiě)localStorage方法

const local = (function(KEY){
  return {
    set: value=>{ localStorage.setItem(KEY, value) },
    get: ()=>localStorage.getItem(KEY),
    check: ()=>localStorage.getItem(KEY) != undefined
  };
})("todo");

然后幾個(gè)輔助的方法:

// 制造一個(gè)新的item
function generateItem(value) {
  return {
    id: _.uniqueId(),
    active: true,
    value
  }
}

// 判斷當(dāng)前的item是否正在展示
function include(active, filter) {
  return filter === "ALL" || (active && filter === "ACTIVE")  || (!active && filter === "COMPLETED");
}

// 獲取頁(yè)面上需要展示的items
function getShowedItems(items, filter) {
  let showedItems = [], keys = Object.keys(items);
  for(let i = 0; i < keys.length; i++){
    let item = items[keys[i]];

    if(include(item.active, filter)) {
      showedItems.push(item);
    }
  }
  return showedItems;
}

初始化的時(shí)候,獲取localStorage中的值,或者給一個(gè)默認(rèn)值:

let defaultTodo;
(function(){
  if(local.check()) {
    defaultTodo = JSON.parse(local.get());
  } else {
    defaultTodo = {
      items: {},
      filter: "ALL", // ALL, COMPLETED, ACTIVE
      count: 0,
      showedItems: [],
      hasCompleted: false
    }
  }
})();

注:在這里提一句,由于我不喜歡文檔中把所有的處理方法放在一個(gè)函數(shù)里面的方式,所以我寫(xiě)了一個(gè)方法,把reducers分開(kāi)成多個(gè)函數(shù)

// 很簡(jiǎn)單,其實(shí)就是循環(huán)調(diào)用。。。
export function combine(reducers){
  return (state, action) => {
    for(let key in reducers) {
      if(reducers.hasOwnProperty(key)) {
          state = reducers[key](state, action) || state;
      }
    }
    return state;
  }
} 

下面上所有的reducers,具體邏輯就不多說(shuō)了:

let exports = {};
exports.insertItem = function(state = defaultTodo, action) {
  const type = action.type;

  if(type === TODO_INSERT_ITEM) {
    let { count, items, filter, showedItems } = state;
    let item = generateItem(action.value);

    items = {
      ...items,
      [item.id] : item 
    }

    count = count + 1;
    
    state = {
      ...state,
      items,
      count,
      showedItems: filter !== "COMPLETED" ? getShowedItems(items, filter) : showedItems
    }

    local.set(JSON.stringify(state));
  }

  return state;
}

exports.deleteItem = function(state = defaultTodo, action) {
  const type = action.type;

  if(type === TODO_DELETE_ITEM && state.items[action.id]) {
    let { count, items, filter, hasCompleted } = state;
    let item = items[action.id];

    delete items[action.id];
    if(item.active) count--;
    
    state = {
      ...state,
      items,
      count,
      showedItems: include(item.active, filter) ? getShowedItems(items, filter) : state.showedItems,
      hasCompleted: Object.keys(items).length !== count
    }

    local.set(JSON.stringify(state));
  }

  return state;
}

exports.switchFilter = function(state = defaultTodo, action) {
  const type = action.type;
  if(type === TODO_SWITCH_FILTER && state.filter !== action.filter) {
    state = {
      ...state,
      filter: action.filter,
      showedItems: getShowedItems(state.items, action.filter)
    }

    local.set(JSON.stringify(state));
  }

  return state;
}

exports.clearCompleted = function(state = defaultTodo, action) {
  const type = action.type;
  if(type === TODO_CLEAR_COMPLETED) {
    let { items, filter, showedItems } = state;

    let keys = Object.keys(items);
    let tempItems = {};
    for(let i = 0; i < keys.length; i++) {
      let item = items[keys[i]];
      if(item.active) {
        tempItems[item.id] = item;
      }
    }

    state = {
      ...state,
      items: tempItems,
      showedItems: filter === "ACTIVE" ? showedItems : getShowedItems(tempItems, filter),
      hasCompleted: false
    }
    local.set(JSON.stringify(state));
  }

  return state;
}

exports.toggleActive = function(state = defaultTodo, action) {
  const { type, id } = action;

  if(type === TODO_TOGGLE_ACTIVE && state.items[id]) {
    let { items, filter, count, showedItems } = state;
    
    let item = items[id];
    item.active = !item.active;
    
    items = {
      ...items,
      [id]: item
    };

    if(item.active) count++; // 如果變?yōu)閍ctive
    else count--; // 如果變?yōu)閏ompleted

    state = {
      ...state,
      items,
      count,
      showedItems: getShowedItems(items, filter),
      hasCompleted: Object.keys(items).length !== count
    }

    local.set(JSON.stringify(state));
  }
  return state;
}

exports.toggleAll = function(state = defaultTodo, action) {
  const { type, active } = action;

  if(type === TODO_TOGGLE_ALL) {
    let { items, filter, showedItems } = state;
    let keys = Object.keys(items);
    
    for(let i = 0; i < keys.length; i++) {
      items[keys[i]].active = active;
    }

    let count = active ? keys.length : 0; 

    state = {
      ...state,
      items,
      count,
      showedItems: include(active, filter) ? getShowedItems(items, filter) : showedItems,
      hasCompleted: !active
    }

    local.set(JSON.stringify(state));
  }
  return state;
}

exports.changeValue = function(state = defaultTodo, action){
  const { type, id } = action;

  if(type === TODO_CHANGE_VALUE && state.items[id]) {
    let { items, filter, showedItems } = state;
    let item = items[id];

    item.value = action.value;

    items = {
      ...items,
      [id]: item    
    };

    state = {
      ...state,
      items,
      showedItems: include(item.active, filter) ? getShowedItems(items, filter) : showedItems
    }
    local.set(JSON.stringify(state));
  }
  return state;
}

export default combine(exports); // 用combine方法包裹

Reducers中,我在很多的showedItems都做了是否發(fā)生改變的檢查,如果沒(méi)有發(fā)生改變,那么就用原來(lái)的,便于在Section組件中,可以避免不必要的重新渲染。雖然,在我這里似乎沒(méi)有什么用。不過(guò)對(duì)復(fù)雜的項(xiàng)目還是有必要的。

Views/Todos.js
import React from "react";
import Header from "containers/ToDo/Header";
import Footer from "containers/ToDo/Footer";
import Section from "containers/ToDo/Section";
import "components/ToDo/index.scss";

export default class ToDo extends React.Component {
  constructor(props) {
    super(props);
  }

  render(){
    return (
      
) } }
Contianers Header.js

Header.js主要負(fù)責(zé)logo的渲染,和那個(gè)input框的功能。

利用controlled component對(duì)input的值進(jìn)行控制,然后監(jiān)聽(tīng)鍵盤(pán)來(lái)判斷是輸入還是提交。

import React from "react";
import { CONTROLS } from "utils/KEYCODE";
import { connect } from "react-redux";
import { insertItem } from "actions/todo";

class Header extends React.Component {
  constructor(props) {
    super(props);

    this.state = {
      value: ""
    };
  }

  onChange = (e)=>{
    let value = e.target.value;
    this.setState({
      value
    });
  }

  onKeyDown = (e)=>{
    let keyCode = e.keyCode;

    if(keyCode === CONTROLS.ENTER && this.state.value !== "") {
      this.props.insertItem(this.state.value);
      this.setState({
        value: ""
      });

      e.preventDefault();
      e.stopPropagation();
    }
  }

  render(){
    return (
      

todos

) } } export default connect(null, { insertItem })(Header);
Footer.js

Footer主要是用于展示數(shù)量filter, Clear Completed按鈕

import React, { PropTypes } from "react";
import { connect } from "react-redux";
import { switchFilter, clearCompleted } from "actions/todo";

class Footer extends React.Component {
  constructor(props) {
    super(props);
  }

  switchFilter = (filter)=>{
    this.props.switchFilter(filter.toUpperCase());
  }

  render(){
    const { count, hasCompleted, filter, clearCompleted } = this.props;

    if(count === 0 && !hasCompleted) return null;

    return (
      
    )
  }
}

Footer.propTypes = {
  count: PropTypes.number.isRequired,
  hasCompleted: PropTypes.bool.isRequired,
  filter: PropTypes.oneOf(["ALL", "ACTIVE", "COMPLETED"]).isRequired
}

function mapStateToProps(state){
  let {
    todo: {
      count,
      hasCompleted,
      filter
    }
  } = state;

  return {
    count,
    hasCompleted,
    filter
  }
}

export default connect(mapStateToProps, { switchFilter, clearCompleted })(Footer);
Section.js

Section包含Todos的列表,還有刪除, 改變狀態(tài)修改value, toggle all等功能。

import React, { PropTypes } from "react";
import { connect } from "react-redux";
import { deleteItem, toggleActive, toggleAll, changeValue } from "actions/todo";
import Item from "components/ToDo/Item";

class Section extends React.Component {
  constructor(props) {
    super(props);
  }

  render(){
    const { showedItems=[], count, toggleAll, changeValue, deleteItem, toggleActive, hasCompleted } = this.props;

    return (
      
{ toggleAll(count === 0) }} checked={count === 0 && hasCompleted} />
    { showedItems.map(item=>) }
) } } Section.propTypes = { showedItems: PropTypes.arrayOf(PropTypes.object).isRequired, count: PropTypes.number.isRequired } function mapStateToProps(state) { let { todo: { showedItems, count, hasCompleted } } = state; return { showedItems, count, hasCompleted }; } export default connect(mapStateToProps, { deleteItem, toggleActive, toggleAll, changeValue })(Section);
Components Item.js
import React from "react";
import ReactDOM from "react-dom";

export default class Item extends React.Component {
  constructor(props) {
    super(props);

    this.state = { value: props.value, editing: false };
  }

  componentDidUpdate() {
    if(this.state.editing) {
      var node = ReactDOM.findDOMNode(this.edit);
      node.focus();
    }
  }

  inputInstance = (input) => {
    this.edit = input;
  }

  onToggle = (e)=>{
    this.props.toggleActive(this.props.id, !e.target.checked);
  }

  onValueChange = (e)=>{
    this.props.onValueChange(this.props.id, e.target.value);
    this.setState({
      editing: false
    });
  }

  onEditChange = (e)=>{
    this.setState({
      value: e.target.value
    });
  }

  onDoubleClick = (e)=>{
    this.setState({
      editing: true
    });
  }

  render(){
    let { id, active, onItemDelete, onValueChange } = this.props;
    let { value, editing } = this.state;

    return (
      
  • { editing || (
    ) } { editing && }
  • ) } }

    寫(xiě)組件的時(shí)候,感覺(jué)代碼貼出來(lái)看看就好了。需要講解的不多。。。

    文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

    轉(zhuǎn)載請(qǐng)注明本文地址:http://m.specialneedsforspecialkids.com/yun/81325.html

    相關(guān)文章

    • redux —— 入門(mén)實(shí)例 TodoList

      摘要:入門(mén)實(shí)例前端技術(shù)真是日新月異,搞完不搭配個(gè)數(shù)據(jù)流都不好意思了。關(guān)于的用法,這只是基礎(chǔ)入門(mén)的部分,還有的多的搞基操作,比如異步數(shù)據(jù)流和配合。 redux —— 入門(mén)實(shí)例 TodoListshowImg(https://segmentfault.com/img/bVtSeH); Tip 前端技術(shù)真是日新月異,搞完 React 不搭配個(gè)數(shù)據(jù)流都不好意思了。滿懷期待的心去翻了翻 flux,簡(jiǎn)直...

      SKYZACK 評(píng)論0 收藏0
    • Redux 入門(mén)

      摘要:系列文章入門(mén)本文進(jìn)階番外篇狀態(tài)管理,第一次聽(tīng)到這個(gè)詞要追溯到去年年底。只讀的唯一改變的方法就是觸發(fā),是一個(gè)用于描述已發(fā)生事件的普通對(duì)象。沒(méi)有特殊情況沒(méi)有副作用,沒(méi)有請(qǐng)求沒(méi)有變量修改,只進(jìn)行單純執(zhí)行計(jì)算。 系列文章: Redux 入門(mén)(本文) Redux 進(jìn)階 番外篇: Vuex — The core of Vue application 狀態(tài)管理,第一次聽(tīng)到這個(gè)詞要追溯到去年年...

      shusen 評(píng)論0 收藏0
    • MobX入門(mén)TodoList

      摘要:用于簡(jiǎn)單可擴(kuò)展的狀態(tài)管理,相比有更高的靈活性,文檔參考中文文檔,本文作為入門(mén),介紹一個(gè)簡(jiǎn)單的項(xiàng)目。任務(wù)已完成下一個(gè)任務(wù)修復(fù)谷歌瀏覽器頁(yè)面顯示問(wèn)題提交意見(jiàn)反饋代碼創(chuàng)建在中引入主入口文件設(shè)置參考入門(mén)學(xué)習(xí)總結(jié) MobX用于簡(jiǎn)單、可擴(kuò)展的React狀態(tài)管理,相比Redux有更高的靈活性,文檔參考:MobX中文文檔,本文作為入門(mén),介紹一個(gè)簡(jiǎn)單的TodoList項(xiàng)目。 1. 預(yù)期效果 showIm...

      csRyan 評(píng)論0 收藏0
    • Taro集成Redux快速上手

      摘要:開(kāi)發(fā)前需要安裝和以及一些需要用到的中間件如果在要使用的話,還需要引入這個(gè)庫(kù)或者使用示例下面通過(guò)實(shí)現(xiàn)一個(gè)快速上手。然后開(kāi)始創(chuàng)建處理這兩個(gè)指令的。完成上述三步之后,我們就可以在應(yīng)用的主頁(yè)使用相應(yīng)修改并取得新的數(shù)據(jù)了。 本文適合有一定React和Redux基礎(chǔ)的用戶閱讀。 前言的前言 最近被一款來(lái)自京東凹凸實(shí)驗(yàn)室的多終端開(kāi)發(fā)框架Taro吸粉了,官方對(duì) Taro 的簡(jiǎn)介是使用React語(yǔ)法,一...

      DevYK 評(píng)論0 收藏0
    • 實(shí)例講解react+react-router+redux

      摘要:而函數(shù)式編程就不一樣了,這是模仿我們?nèi)祟?lèi)的思維方式發(fā)明出來(lái)的。數(shù)據(jù)流在中,數(shù)據(jù)的流動(dòng)是單向的,即從父節(jié)點(diǎn)傳遞到子節(jié)點(diǎn)。數(shù)據(jù)流嚴(yán)格的單向數(shù)據(jù)流是架構(gòu)的設(shè)計(jì)核心。 前言 總括: 本文采用react+redux+react-router+less+es6+webpack,以實(shí)現(xiàn)一個(gè)簡(jiǎn)易備忘錄(todolist)為例盡可能全面的講述使用react全家桶實(shí)現(xiàn)一個(gè)完整應(yīng)用的過(guò)程。 代碼地址:Re...

      RiverLi 評(píng)論0 收藏0

    發(fā)表評(píng)論

    0條評(píng)論

    最新活動(dòng)
    閱讀需要支付1元查看
    <