簡書react開發項目總結

react開發簡書用到技術有路由、react-redux、immutable庫,樣式採用styled-components,在App中的代碼以下:javascript

import React from 'react';
import { GlobalStyle } from './styled';
import { Font } from './static/iconfont/iconfont'
import Header from './common/header'
import { Provider } from 'react-redux'
import { BrowserRouter,Route } from 'react-router-dom'
import Home from './pages/home'
import Detail from './pages/detail/loadable'
import Login from './pages/login'
import Write from './pages/write'

import store from './store'
function App() {
return (
<div>
<Provider store = {store}>

<BrowserRouter>
<div>
<Header ></Header>
<Route path = '/' exact component={Home}></Route>
<Route path = '/login' exact component={Login}></Route>
<Route path = '/write' exact component={Write}></Route>
<Route path = '/detail/:id' exact component={Detail}></Route>
</div>
</BrowserRouter>
</Provider>
<Font></Font>
<GlobalStyle></GlobalStyle>
</div>
);
}

export default App;
Provider將頁面所有包裹起來,引入redux創建的store,在store文件夾中有index.js文件和reducer文件;以下圖所示結構:

在index.js文件中代碼以下:前端

import { createStore,applyMiddleware } from 'redux'
import reducer from './reducer'
import thunk from 'redux-thunk'

const composeEnhancers = window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__
const enhancer = composeEnhancers(
applyMiddleware(thunk),
);
const store = createStore(reducer, enhancer);
export default store;

redux提供了
createStore,applyMiddleware兩個方法,createStore負責建立store這個store管理惟一數據源,至於咱們擔憂數據過於龐大的問題,
combineReducers正是用來解決這個問題的,reducer.js文件中代碼以下:
//import { combineReducers } from 'redux'
import { combineReducers } from 'redux-immutable'
//import headerReducer from '../common/header/store/reducer'
import { reducer as headerReducer } from '../common/header/store'
import { reducer as homeReducer } from '../pages/home/store'
import { reducer as detailReducer} from '../pages/detail/store'
import { reducer as loginReducer } from '../pages/login/store'
const reducer = combineReducers({
header:headerReducer,
home:homeReducer,
detail:detailReducer,
login:loginReducer
})
export default reducer
在開發的簡書頁面上有頭部、home、詳情部分、登陸部分,每一個部分都有本身reducer,沒部分的reducer由
combineReducers結合起來,各部分的reducer處理
各自部分的代碼邏輯。
以head頭部爲例結構以下圖:

 

在head部分的store文件夾中有actionType.js文件action.Creaters.js文件、reducer.js文件、index.js文件,actonType至關於事件類型,以下代碼:
export const SEARCH_FOCUS = 'header/search_focus';
export const SARCH_BLUR = 'header/search_blur';
export const CHANGE_LIST = 'header/change_list';
export const MOUSE_ENTER = 'header/mouse_enter'
export const MOUSE_LEAVE = 'header/mouse_leave';
export const change_Page = 'header/chang_page'
這裏之前是字符串,這裏用變量方便調錯,若是報錯能找到是哪一個事件出問題了。
action.Creaters.js代碼以下:
import * as ationType from './actionType'
import axios from 'axios'
import {fromJS} from "immutable";
const getChangeList = (data) =>({
type:ationType.CHANGE_LIST,
data:fromJS(data),
totalPage: Math.ceil(data.length/10)
});

export const SEARCH_FOCUS = () =>({
type:ationType.SEARCH_FOCUS
});

export const SEARCH_BLUR = () =>({
type:ationType.SARCH_BLUR
});
export const mouseEnter = () =>({
type:ationType.MOUSE_ENTER
});
export const mouseLeave = () =>({
type:ationType.MOUSE_LEAVE
});
export const changePageList = (page) =>({
type:ationType.change_Page,
page
})
export const getList = () =>{
return (dispatch) =>{
axios.get('/api/headerList.json').then((res) =>{
const data = res.data.data;
dispatch(getChangeList(data))
}).catch(() =>{
console.log('err')
})
}
}
 redux-thunk引入redux-thunk最重要的思想,就是能夠接受一個返回函數的action creator。若是這個action creator 返回的是一個函數,就執行它,若是不是
,就按照原來的next(action)執行。例如:在簡書開發項目中ajax請求數據就用了這個用處代碼以下:
const getChangeList = (data) =>({
type:ationType.CHANGE_LIST,
data:fromJS(data),
totalPage: Math.ceil(data.length/10)
});
export const getList = () =>{
return (dispatch) =>{
axios.get('/api/headerList.json').then((res) =>{
const data = res.data.data;
dispatch(getChangeList(data))
}).catch(() =>{
console.log('err')
})
}
}
定義的getList方法返回一個ation給reducer,同時dispatch一個ation是getChangeList()函數將ajax獲取的數據接收過來給reducer,代碼以下:
import * as ationType from './actionType'
import { fromJS } from 'immutable'
const defaultState = fromJS(
{
focused:false,
mouseIn:false,
list:[],
page:1,
totalPage:1
}
)
export default (state = defaultState,action) =>{
switch (action.type)
{ case ationType.CHANGE_LIST:
return state.merge({
'list':action.data,
'totalPage':action.totalPage
});
case ationType.SEARCH_FOCUS:
return state.set ('focused', true);
case ationType.SARCH_BLUR:
return state.set ('focused', false);

//可使用merge方法
//state.set ('list', action.data).set('totalPage',action.totalPage);
case ationType.MOUSE_ENTER:
return state.set('mouseIn',true);
case ationType.MOUSE_LEAVE:
return state.set('mouseIn',false);
case ationType.change_Page:
return state.set('page',action.page);
default:
return state;
}
 
 
import * as ationType from './actionType'在這裏須要引入相應的事件集合,在這裏建立action函數把相應的action發送到reducer裏,
在reducer裏進行變動store裏面的狀態,reducer.js代碼以下:
import * as ationType from './actionType'
import { fromJS } from 'immutable'
const defaultState = fromJS(
{
focused:false,
mouseIn:false,
list:[],
page:1,
totalPage:1
}
)
export default (state = defaultState,action) =>{
switch (action.type)
{
case ationType.SEARCH_FOCUS:
return state.set ('focused', true);
case ationType.SARCH_BLUR:
return state.set ('focused', false);
case ationType.CHANGE_LIST:
return state.merge({
'list':action.data,
'totalPage':action.totalPage
})
//可使用merge方法
//state.set ('list', action.data).set('totalPage',action.totalPage);
case ationType.MOUSE_ENTER:
return state.set('mouseIn',true);
case ationType.MOUSE_LEAVE:
return state.set('mouseIn',false);
case ationType.change_Page:
return state.set('page',action.page);
default:
return state;

}
}
在組件中發送getList()action代碼以下:
const mapDispatchToProps = (dispatch) =>{
return {
handleInputFocus (list) {
// (list.size === 0) && dispatch(ationCreaters.getList());
if(list.size<=0){
dispatch(ationCreaters.getList());
}
}
這樣就能夠經數據請求到並渲染到頁面中。
 
在reducer代碼裏引入immutable.js庫。
  • Immutable Data 就是一旦建立,就不能再被更改的數據。對 Immutable 對象的任何修改或添加刪除操做都會返回一個新的 Immutable 對象
  • Immutable 實現的原理是 Persistent Data Structure (持久化數據結構),也就是使用舊數據建立新數據時,要保證舊數據同時可用且不變
  • 同時爲了不 deepCopy 把全部節點都複製一遍帶來的性能損耗, Immutable 使用了 Structural Sharing···· (結構共享),即若是對象樹中一個節點發生變化,只修改這個節點和受它影響的父節點,其它節點則進行共享。

一個說明不可變的例子:

// 原生對象 let a1 = { b: 1, c: { c1: 123 } }; let b1 = a1; b1.b = 2; console.log(a1.b, b1.b); // 2, 2 console.log(a1 === b1); // true console.log(a1.c === b1.c); // true // immutable.js 的Map let a2 = Immutable.fromJS({ b: 1, c: { c1: 123 } }); let b2 = a2.set('b', 2); // 對 Immutable 對象的任何修改或添加刪除操做都會返回一個新的 Immutable 對象 console.log(a2.get('b'), b2.get('b')); // 1, 2 對象 a2 的 b 值並無變成2。 console.log(a2 === b2); // false //若是對象樹中一個節點發生變化,只修改這個節點和受它影響的父節點,其它節點則進行共享。 console.log(a2.get('c') === b2.get('c')); //true

爲何要在React.js中使用Immutable

  • 它是一個徹底獨立的庫,不管基於什麼框架均可以用它。意義在於它彌補了 Javascript 沒有不可變數據結構的問題
  • 因爲是不可變的,能夠放心的對對象進行任意操做。在 React 開發中,頻繁操做state對象或是 store ,配合 immutableJS 快、安全、方便
  • 熟悉 React.js 的都應該知道, React.js 是一個 UI = f(states) 的框架,爲了解決更新的問題, React.js 使用了 virtual dom , virtual dom 經過 diff 修改 dom ,來實現高效的 dom 更新。
  • 可是有一個問題。當 state 更新時,若是數據沒變,你也會去作 virtual dom 的 diff ,這就產生了浪費。這種狀況其實很常見
  • 固然你可能會說,你可使用 PureRenderMixin 來解決呀, PureRenderMixin 是個好東西,咱們能夠用它來解決一部分的上述問題
  • 但 PureRenderMixin 只是簡單的淺比較,不使用於多層比較。那怎麼辦?本身去作複雜比較的話,性能又會很是差
  • 方案就是使用 immutable.js 能夠解決這個問題。由於每一次 state 更新只要有數據改變,那麼 PureRenderMixin 能夠馬上判斷出數據改變,能夠大大提高性能

Immutable 優勢

  • Immutable 下降了 Mutable 帶來的複雜度

可變( Mutable )數據耦合了 Time 和 Value 的概念,形成了數據很難被回溯java

  • 節省內存

Immutable.js 使用了 Structure Sharing 會盡可能複用內存,甚至之前使用的對象也能夠再次被複用。沒有被引用的對象會被垃圾回收react

import { Map} from 'immutable'; let a = Map({ select: 'users', filter: Map({ name: 'Cam' }) }) let b = a.set('select', 'people'); a === b; // false a.get('filter') === b.get('filter'); // true 
  • Undo/Redo,Copy/Paste,甚至時間旅行這些功能作起來小菜一碟

由於每次數據都是不同的,只要把這些數據放到一個數組裏儲存起來,想回退到哪裏就拿出對應數據便可,很容易開發出撤銷重作這種功能。ios

  • 併發安全

傳統的併發很是難作,由於要處理各類數據不一致問題,所以『聰明人』發明了各類鎖來解決。但使用了 Immutable 以後,數據天生是不可變的,併發鎖就不須要了。ajax

  • 擁抱函數式編程

Immutable 自己就是函數式編程中的概念,純函數式編程比面向對象更適用於前端開發。由於只要輸入一致,輸出必然一致,這樣開發的組件更易於調試和組裝。編程

 

Immutable 的幾種數據類型

  • List : 有序索引集,相似 JavaScript 中的 Array 。
  • Map : 無序索引集,相似 JavaScript 中的 Object 。
  • OrderedMap : 有序的 Map ,根據數據的 set() 進行排序。
  • Set : 沒有重複值的集合。
  • OrderedSet : 有序的 Set ,根據數據的 add 進行排序。
  • Stack : 有序集合,支持使用 unshift() 和 shift() 添加和刪除。
  • Range() : 返回一個 Seq.Indexed 類型的集合,這個方法有三個參數, start 表示開始值,默認值爲 0 , end 表示結束值,默認爲無窮大, step 表明每次增大的數值,默認爲 1 .若是 start = end ,則返回空集合。
  • Repeat() : 返回一個 vSeq.Indexe 類型的集合,這個方法有兩個參數, value 表明須要重複的值, times 表明要重複的次數,默認爲無窮大。
  • Record : 一個用於生成 Record 實例的類。相似於 JavaScript 的 Object ,可是隻接收特定字符串爲 key ,具備默認值。
  • Seq : 序列,可是可能不能由具體的數據結構支持。
  • Collection : 是構建全部數據結構的基類,不能夠直接構建

上面那麼多經常使用的也就是 List 和 Mapjson

幾個重要的API

一、fromJS()

  • fromJS() 是最最最經常使用的將原生 JS 數據轉換爲 ImmutableJS 數據的轉換方法。使用方式相似於 JSON.parse() ,接收兩個參數: json 數據和 reviver 函數
  • 在不傳遞 reviver 函數的狀況下,默認將原生 JS 的 Array 轉爲 List , Object 轉爲 Map
// 常見
const t1 = Immutable.fromJS({a: {b: [10, 20, 30]}, c: 40}); console.log(t1); // 不經常使用 const t2 = Immutable.fromJS({a: {b: [10, 20, 30]}, c: 40}, function(key, value) { // 定製轉換方式,下這種就是將Array轉換爲List,Object轉換爲Map const isIndexed = Immutable.Iterable.isIndexed(value); return isIndexed ? value.toList() : value.toOrderedMap(); // true, "b", {b: [10, 20, 30]} // false, "a", {a: {b: [10, 20, 30]}, c: 40} // false, "", {"": {a: {b: [10, 20, 30]}, c: 40}} }); console.log(t2); 

二、toJS()

先來看官網的一段話: immutable 數據應該被看成值而不是對象,值是表示該事件在特定時刻的狀態。這個原則對理解不可變數據的適當使用是最重要的。爲了將 Immutable.js 數據視爲值,就必須使用 Immutable.is() 函數或 .equals() 方法來肯定值相等,而不是肯定對象引用標識的 === 操做符redux

  • 因此 toJS() 就是用來對兩個 immutable 對象進行值比較的。使用方式相似於 Object.is(obj1, obj2) ,接收兩個參數
const map1 = Immutable.Map({a:1, b:1, c:1}); const map2 = Immutable.Map({a:1, b:1, c:1}); // 兩個不一樣的對象 console.log(map1 === map2); // false // 進行值比較 console.log(Immutable.is(map1, map2)); // true // 不只僅只能比較ImmutableJS的類型的數據 console.log(Immutable.is(undefined, undefined)); // true console.log(Immutable.is(null, undefined)); // false console.log(Immutable.is(null, null)); // true console.log(Immutable.is(NaN, NaN)); // true // 區別於 Object.is console.log(Object.is(0, -0) ,Immutable.is(-0, 0)); // false , true 

三、Map

Map 數據類型,對應原生 Object 數組。最最經常使用的 數據結構之一,循環時無序( orderedMap 有序),對象的 key 能夠是任意值。具體看下面的例子axios

console.log(Map().set(List.of(1), 'list-of-one').get(List.of(1))); console.log(Map().set(NaN, 'NaN').get(NaN)); console.log(Map().set(undefined, 'undefined').get(undefined)); console.log(Map().set(null, 'null').get(null)); 
  • 簡單介紹 OrderedMap

OrderedMap 是 Map 的變體,它除了具備 Map 的特性外,還具備順序性,當開發者遍歷 OrderedMap 的實例時,遍歷順序爲該實例中元素的聲明、添加順序。 OrderedMap 比非有序 Map更昂貴,而且可能消耗更多的內存。若是真要求遍歷有序,請使用 List

四、List

List 數據類型,對應原生 Array 數組。和原生數組,最大區別不存在’空位’。 [, , , , ]

console.log(List([,,,,]).toJS());// [undefined, undefined, undefined, undefined] 
相關文章
相關標籤/搜索