react入門之 Redux與flux的比較學(xué)習(xí)

前言

強(qiáng)烈推薦的學(xué)習(xí)資源:《深入淺出React和Redux》
此篇學(xué)習(xí)筆記記錄了對(duì)書中第三章節(jié)的學(xué)習(xí)心得
在學(xué)習(xí)之前佳励,對(duì)react并沒有實(shí)踐經(jīng)驗(yàn)黍判,有過Vuex開發(fā)經(jīng)驗(yàn)惠毁。但是讀完還是收獲很大灯蝴,是用于前期理解Redux概念的一個(gè)很好的讀物颜骤。

總結(jié)

1、在學(xué)習(xí)之前呆躲,有過拿redux和vuex進(jìn)行比較的念頭异逐,但是在看完一遍redux之后,發(fā)現(xiàn)redux的單向數(shù)據(jù)流與vuex的雙向數(shù)據(jù)流思想相差還是蠻大的插掂,所以就不比較了.....
2灰瞻、在閱讀這一本書的redux章節(jié)當(dāng)中,書中的講述順序十分的棒辅甥,從redux前身flux介紹起酝润,逐步深入地過渡到redux,最后再介紹了成熟的react-redux庫(kù)璃弄,這種思路還是蠻不錯(cuò)的要销。
3、感覺直接看概念谢揪,還是沒有vuex的思路清晰蕉陋,因此做了一些擬人化的比喻捐凭,個(gè)人覺得比較受用...

目錄

  1. flux框架介紹
    1.1 flux四大元素
    1.2 flux的擬人化描述
    1.3 flux總結(jié)
  2. Redux框架介紹
    2.1 Redux基本原則
    2.2 Redux要素分析
    2.3 Redux的可改進(jìn)之處
    2.4 搭上大神的順風(fēng)車—————— react-redux

1拨扶、flux框架介紹

1.1 flux四大元素:

  • Dispatcher:根據(jù)注冊(cè)派發(fā)動(dòng)作(action)
  • Store: 存儲(chǔ)數(shù)據(jù),處理數(shù)據(jù)
  • Action:用于驅(qū)動(dòng)Dispatcher
  • View: 用戶界面視圖
Dispatcher

是全局唯一的Dispatcher對(duì)象茁肠,關(guān)系網(wǎng)的中心

// AppDispatcher.js
// 完成聲明即可患民,后續(xù)無需改動(dòng)
// 注冊(cè)action等事件主要在store中被調(diào)用完成
import {Dispatcher} from 'flux';
export default new Dispatcher ();
Store

注冊(cè)(register):把當(dāng)前store注冊(cè)到Dispatcher下,加入dispatcher關(guān)系網(wǎng)
通過emit廣播垦梆、on掛載事件
store需要注冊(cè)到全局唯一的Dispatcher上才有效
flux核心部分:當(dāng)register函數(shù)把一個(gè)回調(diào)函數(shù)注冊(cè)到Dispatcher后匹颤,所有派發(fā)給Dispatcher的action對(duì)象仅孩,都會(huì)傳遞到這個(gè)回調(diào)函數(shù)中

const counterValues = {
    'First': 0,
    'Second': 10,
    'Third': 30
}

// 聲明、生成store對(duì)象
const CounterStore = object.assign({}, EventEmitter.prototype, {
    getCounterValues: function() {
        return counterValues;
    },
    emitChange: function(){
        this.emit(CHANGE_EVENT);             // 廣播事件
    },
    addChangeListener: function(){
        this.on(CHANGE_EVENT, callback);     // 掛載事件
    },
    removeChangeListener: fucntion(){
        this.removeListener(CHANGE_EVENT, callback);      // 移除監(jiān)聽
    }
})


// 把CounterStore注冊(cè)到全局唯一的Dispatcher上印蓖,register函數(shù)接受一個(gè)回調(diào)函數(shù)做參數(shù)
//注冊(cè)token(控制權(quán)令牌)
CounterStore.dispatchToken = AppDispathcer.register((action)=>{
    if(action.type === ActionTypes.INCREMENT){
        // do increment
        // 根據(jù)action對(duì)象辽慕,修改當(dāng)前store中的counterValues變量
    } else if(action.type === ActionTypes.DECREMENT){
        // do decrement 
        // 根據(jù)action對(duì)象,修改當(dāng)前store中的counterValues變量
    }
})   

使用waitFor()函數(shù)赦肃,通過dispatchToken的傳遞溅蛉,實(shí)現(xiàn)同步調(diào)用,滿足多個(gè)store之間的相互依賴關(guān)系他宛;
常用于獲取store中的最新鮮的數(shù)據(jù)

Action

代表一個(gè)動(dòng)作的純數(shù)據(jù)對(duì)象
是js對(duì)象船侧,且不自帶方法,用于驅(qū)動(dòng)Dispatcher厅各,來自用戶的請(qǐng)求
Action并不包含數(shù)據(jù)處理邏輯镜撩,而是調(diào)用函數(shù),來創(chuàng)建對(duì)應(yīng)的action對(duì)象

// ActionTypes.js
export const INCREMENT = 'increment';
export const DECREMENT = 'decrement';
// action.js
import * as ActionTypes form './ActionTypes.js';
import AppDispatcher from './AppDispatcher.js'

export const increment = (counterCaption) => {
    AppDispatcher.dispatch({
        type: ActionTypes.INCREMENT,       // action對(duì)象類型
        counterCaption:counterCaption      // 用于標(biāo)識(shí)發(fā)出action的來源(即頁面元素)
    })
}
View

用戶在界面中調(diào)用action

// react組件中的事件
onClickBtn() {
    // increment已經(jīng)在對(duì)應(yīng)的store中完成注冊(cè)队塘,Dispactcher可識(shí)別
    Actions.increment(this, props.caption)袁梗;
}

1.2 flux的擬人化描述

Dispatcher:
在十字路口中央指揮交通的交警,不會(huì)離開工作地點(diǎn)人灼,是唯一的围段;
當(dāng)有人督促我派發(fā)(dispatch)一下action,我就要打電話給我的小協(xié)警了投放,叫他趕緊來把這個(gè)家伙的事處理一下奈泪;

Store:
注冊(cè):協(xié)警把自己的電話號(hào)碼給了十字路口的交警并告訴他:“發(fā)生交通事故,就打這個(gè)電話找我灸芳,我來處理現(xiàn)場(chǎng)”涝桅;
emit廣播事件:有人叫我去處理交通事故;
on掛載事件:如果有人叫我去處理交通事故烙样,我要給出的反應(yīng)冯遂;

view
路上的車主,一旦和別人的車撞上了谒获,我要發(fā)出一個(gè)action(下車跑去找交警告訴交警我的事故屬于哪種類型)讓交警知道我撞車了蛤肌,不然他不會(huì)理我的;

action
車主督促交警批狱,趕緊把我的action派發(fā)(dispatch)出去裸准,讓協(xié)警快來處理一下;


1.3 flux總結(jié)

flux的目的:糾正MVC框架的無法禁絕view與model通信的缺點(diǎn)赔硫;

flux的做法:store只有g(shù)et方法炒俱,沒有set方法;因此view只能通過get獲取store狀態(tài),不能修改狀態(tài)权悟;如果想要修改store狀態(tài)砸王,只能派發(fā)一個(gè)action給Dispatcher,由action中ActionTypes對(duì)應(yīng)的store方法去修改store本身峦阁。

flux的缺點(diǎn)

  • store之間的依賴:需要建立依賴馏段,需要token
  • 可以但是很難進(jìn)行服務(wù)器端渲染(尚不理解)
  • store替換后婶博,無法保持原有存儲(chǔ)狀態(tài)(指在開發(fā)中皂股,store邏輯的修改無法熱加載)

2途戒、Redux框架介紹

2.1 Redux基本原則:

  • 繼承Flux基本原則:?jiǎn)蜗驍?shù)據(jù)流
  • 唯一數(shù)據(jù)源
  • 保持狀態(tài)只讀
  • 只有純函數(shù)能改變數(shù)據(jù)
1.唯一數(shù)據(jù)源

Flux:利用Dispatcher的waitFor方法,保證多個(gè)store之間的依賴與更新順序 ==> 數(shù)據(jù)冗余件豌、應(yīng)用復(fù)雜
Redux:所有state只保存在一個(gè)store中疮方,整個(gè)應(yīng)用只有一個(gè)store,狀態(tài)是一個(gè)樹形對(duì)象茧彤,每個(gè)組件使用狀態(tài)樹上的一部分?jǐn)?shù)據(jù)

2.保持狀態(tài)只讀

狀態(tài)只可讀骡显,不可直接修改
渲染原則:UI = render(state) <===> 界面只根據(jù)State進(jìn)行渲染
與Flux相同,必須通過action對(duì)象才能修改store狀態(tài)

3.只有純函數(shù)能改變數(shù)據(jù)

純函數(shù):指不依賴于且不改變它作用域之外的變量狀態(tài)的函數(shù)曾掂,也就是說函數(shù)的返回結(jié)果必須完全由傳入的參數(shù)決定惫谤。

reducer(state, action)
reducer函數(shù),接受兩個(gè)參數(shù)珠洗,第一個(gè)參數(shù)state是當(dāng)前的狀態(tài)(最新的store.state)溜歪,第二個(gè)參數(shù)action是接收到的action對(duì)象;reducer根據(jù)state與action的值產(chǎn)生并返回一個(gè)新的對(duì)象许蓖,返回的這一個(gè)對(duì)象用來組裝新狀態(tài)對(duì)象蝴猪。


2.2 Redux要素分析

  • Store:存儲(chǔ)數(shù)據(jù)
  • Reducer:根據(jù)Action+state替換state,而非直接修改
  • Aciton:定義Action對(duì)象
  • Component:調(diào)用action
1.Store

在Flux中膊爪,Dispatcher的作用:把a(bǔ)ction對(duì)象分發(fā)給不同的自阱、已注冊(cè)的store;
在redux中米酬,只有一個(gè)store沛豌,是唯一的分發(fā)對(duì)象,因此將Dispatcher對(duì)象簡(jiǎn)化為store對(duì)象中的一個(gè)函數(shù)dispatch赃额。

使用createStore創(chuàng)建整個(gè)應(yīng)用唯一的store加派,并且暴露到全局;
組件使用getOwnState函數(shù)用于從store中獲得狀態(tài)

import {createStore} from 'redux';
import reducer from './Reducer.js';

const counterValues = {
    'First': 0,
    'Second': 10,
    'Third': 20
}

const store = createStore(reducer, initValues);   // reducer表示更新狀態(tài)的reducer跳芳,initValues是狀態(tài)的初始值

export default store;

2.Reducer

reducer <===> redux與flux對(duì)state的操作差異
flux:直接修改state的值
redux:修改應(yīng)用狀態(tài)芍锦,并不能直接修改狀態(tài)上的值,而是創(chuàng)建一個(gè)新的狀態(tài)對(duì)象返回給Redux筛严,由Redux組裝新狀態(tài)對(duì)象醉旦。

// Flux版本的action
// Flux: 直接修改store狀態(tài)值
CounterStore.dispatchToken = AppDispatcher.register( (action) => {
    if(action.type === AcitonTypes.INCREMENT) {
        counterValues[action.counterCaption]++;
        CounterStore.emitChange();
    } else if(action.type === AcitonTypes.DECREMENT){
        counterValues[action.counterCaption]--;
        CounterStore.emitChange();
    }
})
// Redux版本的action
// 根據(jù)state與action的值產(chǎn)生并返回一個(gè)新的對(duì)象
// 返回的這一個(gè)對(duì)象用來組裝新狀態(tài)對(duì)象。  
function reducer (state,action) {
    const {counterCaption} = action;

    // 返回的對(duì)象是一個(gè)新的狀態(tài)樹
    // ... 擴(kuò)展操作符
    // ...state表示擴(kuò)展拆分state數(shù)據(jù)桨啃,去除了最頂層的樹結(jié)構(gòu)车胡,暴露二級(jí)節(jié)點(diǎn)
    // [counterCaption]: newData 則體現(xiàn)了redux狀態(tài)樹的設(shè)計(jì)
    // 使用組件的caption作為狀態(tài)樹的對(duì)應(yīng)子數(shù)據(jù)字段
    switch (action.type) {
        case ActionTypes.INCREMENT: 
            return {...state, [counterCaption]: state[counterCaption] +1};
        case ActionTypes.DECREMENT: 
            return {...state, [counterCaption]: state[counterCaption] -1};
        default: 
            return state
    }
}
Action

flux:Action構(gòu)造函數(shù)不返回什么,而是把構(gòu)造的動(dòng)作函數(shù)立刻通過調(diào)用dispatcher函數(shù)派發(fā)出去

// Flux之Action
export const increment = (counterCaption) => {
    AppDispatcher.dispatch({
        type: ActionTypes.INCREMENT,       // action對(duì)象類型
        counterCaption:counterCaption      // 用于標(biāo)識(shí)發(fā)出action的來源(即頁面元素)
    })
}

reudx:每個(gè)Action構(gòu)造函數(shù)返回一個(gè)action對(duì)象 == > 返回一個(gè)對(duì)象照瘾,把處理對(duì)象的工作交給調(diào)用者

// Redux之Action
export const increment = (counterCaption) => {
    return {
        type: ActionTypes.INCREMENT,       // action對(duì)象類型
        counterCaption:counterCaption      // 用于標(biāo)識(shí)發(fā)出action的來源(即頁面元素)
    })
}



Component

用于聲明綁定派發(fā)action事件

onIncrement() {
    // 通過dispatch派發(fā)aciton
    store.dispatch(Actions.increment(this.props.caption));
}

render() {
    const value = this.state.value;
    const {caption} = this.props;
    return (
        <div>
            <button onclick={this.onIncrement}>+</button>
        </div>
    );
}

2.3 Redux的可改進(jìn)之處

1. 組件功能單一化

當(dāng)前組件具有兩個(gè)功能:1匈棘、派發(fā)Action,更新state樹析命;2主卫、根據(jù)state與props渲染用戶界面
為了使組件專注于單一功能 ===> 拆分組件(容器組件、展示組件)
容器組件:外層組件鹃愤,負(fù)責(zé)與store交互簇搅;
展示組件:內(nèi)層組件,負(fù)責(zé)渲染界面软吐,無狀態(tài)瘩将;

store 《====》 容器組件 ===(傳遞props)==》 展示組件 《====》 React界面

2.context全局訪問對(duì)象

理想目標(biāo)
單個(gè)應(yīng)用最好只導(dǎo)入一次全局Store,在最頂層React組件的位置凹耙;
為提高組件的復(fù)用性姿现,其余組件應(yīng)該避免直接導(dǎo)入Store;
為了滿足以上原則而出現(xiàn)的缺點(diǎn):在一個(gè)多層嵌套組件結(jié)構(gòu)中肖抱,當(dāng)只有最里層組件需要使用store备典,為了將sotre從最外層傳到最里層,必須在所有中間組件中使用props逐級(jí)傳遞state意述。

Context:在樹狀組件中的所有組件都可訪問的一個(gè)共同對(duì)象提佣,上下文環(huán)境
當(dāng)上級(jí)組件宣稱自己支持context,并且提供一個(gè)函數(shù)來返回代表context的對(duì)象荤崇,所有子孫組件可在宣稱(import)后通過this.context訪問到這個(gè)共同的環(huán)境變量镐依。

Provider類組件實(shí)現(xiàn)Context

// Provider類組件實(shí)現(xiàn)Context

import {PropTypes, Component} from 'react';

class Provider extends Component {
    getChildContext() {
        return {
            store: this.props.store
        };
    }
    
    render() {
        // 渲染子組件   props.children代表子組件
        return this.props.children;
    }
}

// 使Provider被React認(rèn)可,成為一個(gè)Context提供者天试,必須指定childContextTypes屬性
Provider.childContextTypes = {
    store: PropTypes.object
};

Provider提供Context,暴露到所有子組件中

// Provider的實(shí)踐使用
// index.js  應(yīng)用入口文件
import store from './Store.js'
import Provider from './Provider.js';

// ControlPanel是ReactDOM的頂層組件槐壳,現(xiàn)在被Provider組件包住后,Provider成為頂層組件
// Provider內(nèi)層包裹的所有
ReactDOM.render (
    <Provider store={store}>
        <ControlPanel />
    </Provider>,
    document.getElementById('root')
)

在子組件中使用Context

// 第一步: 給組件類的contextTypes屬性賦值
CounterContainer.contextTypes = {
    store: PropTypes.object
}

// 第二步:在構(gòu)造函數(shù)中用上第二個(gè)參數(shù)context
constructor(props, context) {
    // 寫法一:
    super(props, context);
    // 寫法二:
    super(...arguments);
}


// 第三步:通過this.context.store訪問store
getOwnState() {
    return {
        // [this.props.catption]用于獲取狀態(tài)樹中的某個(gè)二級(jí)狀態(tài)
        value: this.context.store.getState()[this.props.catption]
    }
}


2.4 搭上大神的順風(fēng)車—————— react-redux

對(duì)于Redux的兩個(gè)改進(jìn)在實(shí)現(xiàn)在實(shí)現(xiàn)上仍然具有一定的復(fù)雜性與機(jī)械性喜每,因此已經(jīng)有人創(chuàng)建了一個(gè)庫(kù)來幫我們完成這些工作(組件拆分與context)
react-redux庫(kù)兩大功能:
1务唐、connect:連接容器組件與展示組件
2、Provider:我們不再需要自己實(shí)現(xiàn)Provider來獲取context带兜,可以使用庫(kù)提供的Provider

connect

包含了兩個(gè)函數(shù)中執(zhí)行:connectconnect返回函數(shù)
connect(mapStateToProps, mapDispatchToProps)的傳入?yún)?shù)是兩個(gè)映射函數(shù),返回值是一個(gè)函數(shù)
connect函數(shù)作用:
1枫笛、向內(nèi)傳遞state:把store上的狀態(tài)轉(zhuǎn)化為內(nèi)層展示組件的props;
2刚照、向外轉(zhuǎn)發(fā)Action:把內(nèi)層展示組件中的用戶動(dòng)作轉(zhuǎn)化為派送給store的動(dòng)作

export default connect(mapStateToProps, mapDispatchToProps)(Counter);


// mapStateToProps函數(shù)刑巧,向內(nèi)傳遞state => props
function mapStateToProps(state, ownProps) {
    return {
        value: state[ownProps.caption]
    }
}

// mapDispatchToProps函數(shù),向外轉(zhuǎn)發(fā)Action
// ownProps屬性就是,直接傳遞給外層容器組件的props
function mapDispatchToProps(dispatch, ownProps) {
    return {
        onIncrement: () => {
            dispatch(Actions.increment(ownProps.caption));
        },
        onDecrement: () => {
            dispatch(Actions.decrement(ownProps.captions))
        }
    }
}

Provider

import {Provider} from 'react-redux';

react-redux庫(kù)的提供的Provider幾乎相同啊楚,但更加嚴(yán)謹(jǐn)吠冤;
react-redux庫(kù)要求store必須是一個(gè)包含以下三個(gè)函數(shù)的object:

  • subscribe
  • dispatch
  • getState

react-redux還提供了componentWillReceiveProps鉤子,用于每次重新渲染時(shí)調(diào)用

redux總結(jié) & 與flux的比較

  1. 全局唯一數(shù)據(jù)源恭理,store
  2. reducer替換狀態(tài)樹拯辙,而非直接修改值
  3. Provider優(yōu)化props傳遞
  4. 組件拆解,功能單一化

react項(xiàng)目常見組織結(jié)構(gòu)

  • ReactApp
    |---reducers // 所有的reducer
    |---actions // 所有的action構(gòu)造函數(shù)
    |---components // 所有的展示組件
    |---containers // 所有的容器組件
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末颜价,一起剝皮案震驚了整個(gè)濱河市涯保,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌周伦,老刑警劉巖夕春,帶你破解...
    沈念sama閱讀 216,324評(píng)論 6 498
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異专挪,居然都是意外死亡撇他,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,356評(píng)論 3 392
  • 文/潘曉璐 我一進(jìn)店門狈蚤,熙熙樓的掌柜王于貴愁眉苦臉地迎上來困肩,“玉大人,你說我怎么就攤上這事脆侮⌒炕” “怎么了?”我有些...
    開封第一講書人閱讀 162,328評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵靖避,是天一觀的道長(zhǎng)潭枣。 經(jīng)常有香客問我,道長(zhǎng)幻捏,這世上最難降的妖魔是什么盆犁? 我笑而不...
    開封第一講書人閱讀 58,147評(píng)論 1 292
  • 正文 為了忘掉前任,我火速辦了婚禮篡九,結(jié)果婚禮上谐岁,老公的妹妹穿的比我還像新娘。我一直安慰自己榛臼,他們只是感情好伊佃,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,160評(píng)論 6 388
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著沛善,像睡著了一般航揉。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上金刁,一...
    開封第一講書人閱讀 51,115評(píng)論 1 296
  • 那天帅涂,我揣著相機(jī)與錄音议薪,去河邊找鬼。 笑死媳友,一個(gè)胖子當(dāng)著我的面吹牛斯议,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播庆锦,決...
    沈念sama閱讀 40,025評(píng)論 3 417
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼轧葛!你這毒婦竟也來了搂抒?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 38,867評(píng)論 0 274
  • 序言:老撾萬榮一對(duì)情侶失蹤尿扯,失蹤者是張志新(化名)和其女友劉穎求晶,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體衷笋,經(jīng)...
    沈念sama閱讀 45,307評(píng)論 1 310
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡芳杏,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,528評(píng)論 2 332
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了辟宗。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片爵赵。...
    茶點(diǎn)故事閱讀 39,688評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖泊脐,靈堂內(nèi)的尸體忽然破棺而出空幻,到底是詐尸還是另有隱情,我是刑警寧澤容客,帶...
    沈念sama閱讀 35,409評(píng)論 5 343
  • 正文 年R本政府宣布秕铛,位于F島的核電站,受9級(jí)特大地震影響缩挑,放射性物質(zhì)發(fā)生泄漏但两。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,001評(píng)論 3 325
  • 文/蒙蒙 一供置、第九天 我趴在偏房一處隱蔽的房頂上張望谨湘。 院中可真熱鬧,春花似錦芥丧、人聲如沸悲关。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,657評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽寓辱。三九已至,卻和暖如春赤拒,著一層夾襖步出監(jiān)牢的瞬間秫筏,已是汗流浹背诱鞠。 一陣腳步聲響...
    開封第一講書人閱讀 32,811評(píng)論 1 268
  • 我被黑心中介騙來泰國(guó)打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留这敬,地道東北人航夺。 一個(gè)月前我還...
    沈念sama閱讀 47,685評(píng)論 2 368
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像崔涂,于是被迫代替她去往敵國(guó)和親阳掐。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,573評(píng)論 2 353

推薦閱讀更多精彩內(nèi)容

  • 學(xué)習(xí)必備要點(diǎn): 首先弄明白冷蚂,Redux在使用React開發(fā)應(yīng)用時(shí)缭保,起到什么作用——狀態(tài)集中管理 弄清楚Redux是...
    賀賀v5閱讀 8,896評(píng)論 10 58
  • 看到這篇文章build an image gallery using redux saga,覺得寫的不錯(cuò)蝙茶,長(zhǎng)短也適...
    smartphp閱讀 6,154評(píng)論 1 29
  • 一艺骂、CMS管理系統(tǒng)功能 CMS是ContentManagementSystem的縮寫,意為"內(nèi)容管理系統(tǒng)"隆夯。 CM...
    默默先生Alec閱讀 5,339評(píng)論 0 7
  • 前言 本文 有配套視頻钳恕,可以酌情觀看。 文中內(nèi)容因各人理解不同蹄衷,可能會(huì)有所偏差忧额,歡迎朋友們聯(lián)系我討論。 文中所有內(nèi)...
    珍此良辰閱讀 11,904評(píng)論 23 111
  • 要說些什么呢愧口?我也不清楚宙址。 那天做了個(gè)測(cè)試,是關(guān)于心理年齡的调卑,測(cè)得的心理年齡是21歲左右抡砂,和我的實(shí)際年齡一樣啊,而...
    香蕉味兒的橘子閱讀 169評(píng)論 0 0