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
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
能夠馬上判斷出數據改變,能夠大大提高性能可變( 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
由於每次數據都是不同的,只要把這些數據放到一個數組裏儲存起來,想回退到哪裏就拿出對應數據便可,很容易開發出撤銷重作這種功能。ios
傳統的併發很是難作,由於要處理各類數據不一致問題,所以『聰明人』發明了各類鎖來解決。但使用了 Immutable
以後,數據天生是不可變的,併發鎖就不須要了。ajax
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
和 Map
json
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);
先來看官網的一段話: 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
數據類型,對應原生 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
是 Map
的變體,它除了具備 Map
的特性外,還具備順序性,當開發者遍歷 OrderedMap
的實例時,遍歷順序爲該實例中元素的聲明、添加順序。 OrderedMap
比非有序 Map
更昂貴,而且可能消耗更多的內存。若是真要求遍歷有序,請使用 List
List
數據類型,對應原生 Array
數組。和原生數組,最大區別不存在’空位’。 [, , , , ]
console.log(List([,,,,]).toJS());// [undefined, undefined, undefined, undefined]