成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專欄INFORMATION COLUMN

Redux 進(jìn)階

zone / 1378人閱讀

摘要:系列文章入門進(jìn)階本文番外篇在之前的文章中,我們已經(jīng)了解了到底是什么,用來(lái)處理什么樣的問(wèn)題,并創(chuàng)建了一個(gè)簡(jiǎn)單的。啟動(dòng)應(yīng)用之后,就能在控制臺(tái)中看到一下的輸出。現(xiàn)在,如果你刷新界面就應(yīng)該能看到控制臺(tái)中已經(jīng)輸出了為和的。

系列文章:

Redux 入門

Redux 進(jìn)階(本文)

番外篇: Vuex — The core of Vue application

在之前的文章中,我們已經(jīng)了解了 Redux 到底是什么,用來(lái)處理什么樣的問(wèn)題,并創(chuàng)建了一個(gè)簡(jiǎn)單的 TodoMVC Demo。但是,我們同樣遺留了一些問(wèn)題沒(méi)有處理,比如:異步處理、中間件、模板綁定等,這些問(wèn)題我們將在這篇文章中通過(guò)一個(gè)簡(jiǎn)單的天氣預(yù)報(bào) Demo 來(lái)一一梳理(查看源碼點(diǎn)這里)。

在開(kāi)始新的內(nèi)容之前,先快速回顧一下上一篇的內(nèi)容。

Action, Reducer & Store

創(chuàng)建一個(gè)基于 Redux 狀態(tài)管理的應(yīng)用時(shí),我們還是從創(chuàng)建 Redux 的核心開(kāi)始。

首先,建立 Action。假設(shè),發(fā)出請(qǐng)求和收到請(qǐng)求之間有一個(gè) loading 的狀態(tài),那么,我們將查詢天氣這個(gè)行為劃分為 2 個(gè) action,并為此創(chuàng)建 2 個(gè)工廠函數(shù)。

export const QUERY_WEATHER_TODAY = "QUERY_WEATHER_TODAY"
export const RECEIVE_WEATHER_TODAY = "RECEIVE_WEATHER_TODAY"

export function queryWeatherToday(city) {
    return {
        type: QUERY_WEATHER_TODAY,
        city
    }
}

export function receiveWeatherToday(weatherToday) {
    return {
        type: RECEIVE_WEATHER_TODAY,
        weatherToday
    }
}

然后,為 Action 創(chuàng)建相應(yīng)的 Reducer,不要忘了 Reducer 必須是一個(gè)純函數(shù)。

export default function WeatherTodayReducer(state = {}, action) {
    switch (action.type) {
        case QUERY_WEATHER_TODAY:
            return { load: true, city: action.city }
        case RECEIVE_WEATHER_TODAY:
            return { ...state, load: false, detail: action.weatherToday}
        default:
            return state
    }
}

最后是 Sotre。

import { createStore } from "redux"
import WeatherForecastReducer from "../reducers"
import actions from "../actions"

let store = createStore(WeatherForecastReducer)
// Log the initial state
console.log("init store", store.getState())

store.dispatch(actions.queryWeatherToday("shanghai"))

console.log(store.getState())

store.dispatch(actions.receiveWeatherToday({}))

console.log(store.getState())

export default store

啟動(dòng)應(yīng)用之后,就能在控制臺(tái)中看到一下的輸出。

回顧了之前的內(nèi)容以后,那我們就進(jìn)入正題,來(lái)看一些新概念。

中間件

相信大家對(duì)中間件這個(gè)詞并不陌生,Redux 中的中間件和其他的中間件略微有些不同。它并不是對(duì)整個(gè) Redux 進(jìn)行包裝,而是對(duì) store.dispatch 方法進(jìn)行的封裝,是 action 與 reducer 之間的擴(kuò)展。

Redux 官網(wǎng)一步一步詳細(xì)地演示了中間件產(chǎn)生的原因及其演變過(guò)程,在此我就不再多做贅述了。

中間件在真正應(yīng)用中是必不可少的一環(huán),或許你不需要寫一個(gè)中間件,但理解它會(huì)對(duì)你運(yùn)用 Redux 編寫代碼會(huì)有很大的幫助。

異步請(qǐng)求

在上一篇文章中有提到,為了保證 reducer 的純凈,Redux 中的異步請(qǐng)求都是由 action 處理。

但是,reducer 需要接收一個(gè)普通的 JS 對(duì)象,action 工廠返回一個(gè)描述事件的簡(jiǎn)單對(duì)象,那我們的異步方法該怎么處理哪?這就需要我們剛才提到的中間件來(lái)幫忙了,添加 redux-thunk 這個(gè)中間件,使我們的 action 得到增強(qiáng),使得 action 不單能返回對(duì)象,還能返回函數(shù),在這個(gè)函數(shù)中還可以發(fā)起其他的 action。

其實(shí),redux-thunk 這個(gè)中間件也沒(méi)有什么特別之處,在 Redux 官網(wǎng)的案例最后已經(jīng)簡(jiǎn)單地實(shí)現(xiàn)了它。

/**
 * 雖然,中間件是對(duì) store.dispatch 的封裝,但它是添加在整個(gè) store 上
 * 所以,函數(shù)能傳遞 `dispatch` 和 `getState` 作為參數(shù)
 * 
 * redux-thunk 的邏輯就是判斷當(dāng)前的 action 是不是一個(gè)函數(shù),是就執(zhí)行函數(shù),不是就繼續(xù)傳遞 action 給下一個(gè)中間件
 */
const thunk = store => next => action =>
  typeof action === "function" ?
    action(store.dispatch, store.getState) :
    next(action)

于是,我們就修改一下之前的 action,給它添加一個(gè)異步請(qǐng)求。

export const QUERY_WEATHER_TODAY = "QUERY_WEATHER_TODAY"
export const RECEIVE_WEATHER_TODAY = "RECEIVE_WEATHER_TODAY"

const queryWeatherToday = city => ({
    type: QUERY_WEATHER_TODAY,
    city
})

const receiveWeatherToday = weatherToday => ({
    type: RECEIVE_WEATHER_TODAY,
    weatherToday
})

export function fetchWeatherToday(city) {
    return dispatch => {
        dispatch(queryWeatherToday(city))

        return fetch(`http://api.openweathermap.org/data/2.5/weather?q=${city}&APPID=${CONFIG.APPID}`)
            .then(response => response.json())
            .then(data => dispatch(receiveWeatherToday(data)))
    }
}

既然,我們用了中間件,那就要在 createStore 的時(shí)候裝載中間件。

import { createStore, applyMiddleware } from "redux"
import thunkMiddleware from "redux-thunk"
import createLogger from "redux-logger"

import WeatherForecastReducer from "../reducers"
import actions from "../actions"

const loggerMiddleware = createLogger()

const store = createStore(
    WeatherForecastReducer,
    applyMiddleware(
        thunkMiddleware,
        loggerMiddleware
    )
)

store.dispatch(actions.fetchWeatherToday("shanghai"))

export default store

這時(shí),再看看應(yīng)用的控制臺(tái)。

OK,Redux 核心的功能我們基本完成,我們繼續(xù)看看如何將它同界面綁定在一起。

模板綁定

官網(wǎng)的例子都是 Redux 搭配 React,用的是 react-redux;然而,本文一直是以 Angular 來(lái)寫的例子,所以,這里就用到另一個(gè) redux 生態(tài)圈中的項(xiàng)目 angular-redux。它其中包含了 2 個(gè)不同的庫(kù),ng-redux 和 ng2-redux,分別對(duì)應(yīng) Angular 1.x 和 Angular 2 兩個(gè)版本。

當(dāng)然,我們這里使用 ng-redux。之前那些章節(jié)和官網(wǎng)講述的可能相差不大,但這部分就有所區(qū)分了。

react-redux 提供一個(gè)特殊的 React 組件 Provider,它通過(guò) React Context 特性使每個(gè)組件不用顯示地傳遞 store 就能使用它。

ng-redux 當(dāng)然不能使用這種方式,但它可以使用 angular 自己的方式——依賴注入。

ng-redux 是一個(gè) provider,它包含了所有 Redux store 所有的 API,額外只有 2 個(gè) API,分別是 createStoreWithconnect。

其中,createStoreWith 顯而易見(jiàn)是用來(lái)創(chuàng)建一個(gè) store,參數(shù)同 Redux 的 createStore 方法差不多,原有創(chuàng)建 store 的方法就用不到了,之前的 store.js 也就被合并到了應(yīng)用啟動(dòng)的 index.js 里。

import angular from "angular"
import ngRedux from "ng-redux"
import thunkMiddleware from "redux-thunk"
import createLogger from "redux-logger"

import "./assets/main.css"
import WeatherForecastReducer from "./reducers"
import Components from "./components"

const loggerMiddleware = createLogger()

angular.module("WeatherForecastApp", [ngRedux, Components])
    .config($ngReduxProvider => {
        $ngReduxProvider.createStoreWith(
            WeatherForecastReducer,
            [thunkMiddleware, loggerMiddleware]
        )
    })

這樣應(yīng)用的 store 就建立好了。

另一個(gè) API connect 的用法同 react-redux 的 connect 方法差不多,用于將 props 和 actions 綁定到 template 上。

API 簽名是 connect(mapStateToTarget, [mapDispatchToTarget])(target)。

其中,mapStateToTarget 是一個(gè) function,function 的參數(shù)是 state,返回 state 的一部分,即 select;mapDispatchToTarget 可以是對(duì)象或函數(shù),如果是對(duì)象,那么它的每個(gè)屬性都必須是 actions 工廠方法,這些方法會(huì)自動(dòng)地綁定到 target 對(duì)象上,也就是說(shuō),如果用之前定義好的 action,這邊就不需要做任何的修改;如果是函數(shù),那么這個(gè)函數(shù)會(huì)被傳遞 dispatch 作為參數(shù),而且這個(gè)函數(shù)需要返回一個(gè)對(duì)象,如何 dispatch action 就由你自己設(shè)定,同時(shí)這個(gè)對(duì)象的屬性也會(huì)綁定到 target 對(duì)象上。

最后的 target 就是目標(biāo)對(duì)象了,也可以是函數(shù),如果是函數(shù)的話,前面所傳的 2 個(gè)參數(shù)會(huì)作為 target 函數(shù)的參數(shù)。

好了,扯了這么多概念,估計(jì)你也暈了。
Talk is sxxt,show me the code!

// query-city/controller.js
import actions from "../../actions"

export default class QueryCity {
    constructor($ngRedux, $scope) {
        const unsubscribe = $ngRedux.connect(null, actions)(this)
        $scope.$on("$destroy", unsubscribe)
    }
}

// today-weather-board/controller.js
export default class TodayWeatherBoardCtrl {
    constructor($ngRedux, $scope) {
        const unsubscribe = $ngRedux.connect(this.mapStateToThis)(this);
        $scope.$on("$destroy", unsubscribe);
    }

    mapStateToThis(state) {
        return {
            weatherToday: state.weatherToday
        };
    }
}

這樣,controller 是不是變得很簡(jiǎn)潔?

Weather Forecast 部分基本和之前的部分相同,唯一的一處小修改就是把 QueryCity 控制器里添加一個(gè)方法,在方法里調(diào)用 2 個(gè)不同的 action 來(lái)替換之前按鈕上直接綁定的 action。

于是,我們的天氣預(yù)報(bào)應(yīng)用就成了這樣。

路由切換

一個(gè)真實(shí)的項(xiàng)目肯定會(huì)用到路由切換,路由狀態(tài)也是應(yīng)用狀態(tài)的一部分,那么它也應(yīng)當(dāng)由 Redux 來(lái)統(tǒng)一管理。

談到 Angular 的路由,那必須提到 ui-router。那 ui-router 怎么整合到由 Redux 管理的項(xiàng)目中哪?答案是:redux-ui-router。

使用 redux-ui-router 同樣也有 3 點(diǎn)要注意:

使用 store 來(lái)管理應(yīng)用的路由狀態(tài)

使用 action 代替 $state 來(lái)觸發(fā)路由的變更

使用 state 代替 $stateParams 來(lái)作為路由參數(shù)

記住這些就可以動(dòng)手開(kāi)工了。首先,安裝依賴:

npm install angular-ui-router redux-ui-router --save

這里有一點(diǎn)要注意,redux-ui-router 雖然依賴 angular-ui-router,但它不會(huì)幫你自動(dòng)安裝,需要你自己額外手動(dòng)安裝,雖然你項(xiàng)目里不需要引入 angular-ui-router 模塊。

安裝完依賴之后,就把它引入到我們項(xiàng)目中,項(xiàng)目的 index.js 就變?yōu)榱?/p>

import angular from "angular"
import ngRedux from "ng-redux"
import ngReduxUiRouter from "redux-ui-router"
import thunkMiddleware from "redux-thunk"
import createLogger from "redux-logger"

import "./assets/main.css"
import { current, forecast } from "./Router"
import App from "./app/app"
import WeatherForecastReducer from "./reducers"
import Components from "./components"

const loggerMiddleware = createLogger()

angular.module("WeatherForecastApp", [ngReduxUiRouter, ngRedux, App, Components])
    .config(($urlRouterProvider, $stateProvider) => {
        $urlRouterProvider
            .otherwise("/current")

        $stateProvider
            .state("current", current)
            .state("forecast", forecast)
    })
    .config($ngReduxProvider => {
        $ngReduxProvider.createStoreWith(
            WeatherForecastReducer,
            [thunkMiddleware, loggerMiddleware, "ngUiRouterMiddleware"]
        )
    })

項(xiàng)目中只需引入 ngReduxUiRouter 模塊,而不用再引入 ui-router 模塊到應(yīng)用中。ui-router 的路由聲明就不在這里贅述了,網(wǎng)上的資料也是大把大把的。

接著,將 "ngUiRouterMiddleware" 添加到中間件中,這樣距離完工就只剩最后一步了。

那就是修改主 Reducer 文件,將路由的 Reducer 合并到主 Reducer中,

import { combineReducers } from "redux"
import { router } from "redux-ui-router"
import weatherToday from "./WeatherToday"
import weatherForecast from "./WeatherForecast"

export default combineReducers({
    weatherToday,
    weatherForecast,
    router
})

OK,大工告成?,F(xiàn)在,如果你刷新界面就應(yīng)該能看到控制臺(tái)中已經(jīng)輸出了 type@@reduxUiRouter/$stateChangeStart@@reduxUiRouter/$stateChangeSuccess 的 action log。此時(shí),如果頁(yè)面上使用 ui-sref 來(lái)切換應(yīng)用路由狀態(tài)的話,同樣也能看到 redux-logger 輸出的日志。

在這個(gè) Demo 里,我就不直接使用 ui-sref,而是用例子來(lái)說(shuō)明剛剛提到的 3 點(diǎn)中的第二點(diǎn):使用 action 代替 $state 來(lái)觸發(fā)路由的變更。

import { stateGo } from "redux-ui-router"

export default class NavBarCtrl {
    constructor($ngRedux, $scope) {
        const routerAction = { stateGo }
        const unsubscribe = $ngRedux.connect(this.mapStateToThis, routerAction)(this)
        $scope.$on("$destroy", unsubscribe)
    }

    mapStateToThis(state) {
        return {
            router: state.router
        }
    }
}

從代碼中可以看到,先從 redux-ui-router 里引入了 stateGo 方法,然后通過(guò)上一節(jié)所說(shuō)的模板綁定,將這個(gè)方法綁定到當(dāng)前的模板上,于是在模板中就可以使用 $ctrl.stateGo() 方法來(lái)跳轉(zhuǎn)路由。

那為什么說(shuō)這就滿足了剛剛的第二點(diǎn)哪?查看源碼就可以發(fā)現(xiàn),redux-ui-router 提供的 stateGo(to, params, options)等 API 也只是個(gè)再普通不過(guò)的 action 工廠方法,返回一個(gè)特定 type 的 action。

路由的切換是在之前添加的中間件中,做了一個(gè)類似 reducer 的處理,根據(jù)不同的 action type 觸發(fā)不同的路由事件。

舉一反三,通過(guò)模板綁定我們可以獲得當(dāng)前應(yīng)用的 state。那么,我們同樣可以用過(guò)調(diào)用 $ctrl.stateGo() 等方法給路由切換添加參數(shù)來(lái)做到使用 state 代替 $stateParams 來(lái)作為路由參數(shù)

順便說(shuō)一句,redux-ui-router 似乎還沒(méi)有支持 angular-ui-router 中的 View Load Events,如果你看懂了我剛剛所說(shuō)的,那么 pr 走起。

寫在最后

一不小心寫了那么長(zhǎng),文筆又不是很好,不知有多少人看完了,希望大家都有所收獲。

其中,也有不少細(xì)節(jié)也沒(méi)有細(xì)說(shuō),有疑問(wèn)的就留言吧。

在學(xué)習(xí)的過(guò)程中發(fā)現(xiàn)還有不少相關(guān)的知識(shí)可以擴(kuò)展,應(yīng)該還會(huì)有下一篇。

最后,最重要的當(dāng)然是附上源碼。

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

轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/86411.html

相關(guān)文章

  • Redux 莞式教程 之 進(jìn)階

    摘要:進(jìn)階教程原文保持更新寫在前面相信您已經(jīng)看過(guò)簡(jiǎn)明教程,本教程是簡(jiǎn)明教程的實(shí)戰(zhàn)化版本,伴隨源碼分析用的是編寫,看到有疑惑的地方的,可以復(fù)制粘貼到這里在線編譯總覽在的源碼目錄,我們可以看到如下文件結(jié)構(gòu)打醬油的,負(fù)責(zé)在控制臺(tái)顯示警告信息入口文件除去 Redux 進(jìn)階教程 原文(保持更新):https://github.com/kenberkele... 寫在前面 相信您已經(jīng)看過(guò) Redux ...

    岳光 評(píng)論0 收藏0
  • 【React進(jìn)階系列】手寫實(shí)現(xiàn)react-redux api

    簡(jiǎn)介:簡(jiǎn)單實(shí)現(xiàn)react-redux基礎(chǔ)api react-redux api回顧 把store放在context里,所有子組件可以直接拿到store數(shù)據(jù) 使組件層級(jí)中的 connect() 方法都能夠獲得 Redux store 根組件應(yīng)該嵌套在 中 ReactDOM.render( , rootEl ) ReactDOM.render( ...

    劉玉平 評(píng)論0 收藏0
  • redux深入進(jìn)階

    摘要:上一篇文章講解了如何使用,本篇文章將進(jìn)一步深入,從的源碼入手,深入學(xué)習(xí)的中間件機(jī)制。的功能是讓支持異步,讓我們可以在中跟服務(wù)器進(jìn)行交互等操作,而他的實(shí)現(xiàn)。。。 上一篇文章講解了redux如何使用,本篇文章將進(jìn)一步深入,從redux的源碼入手,深入學(xué)習(xí)redux的中間件機(jī)制。在這里我們會(huì)以一個(gè)redux-thunk中間件為例,逐步分解redux的中間機(jī)制如何操作,如何執(zhí)行。 閑話不多說(shuō),...

    omgdog 評(píng)論0 收藏0
  • React-Redux進(jìn)階(像VUEX一樣使用Redux

    摘要:前言是一個(gè)非常實(shí)用的狀態(tài)管理庫(kù),對(duì)于大多數(shù)使用庫(kù)的開(kāi)發(fā)者來(lái)說(shuō),都是會(huì)接觸到的。在使用享受其帶來(lái)的便利的同時(shí),我們也深受其問(wèn)題的困擾。只支持同步,讓狀態(tài)可預(yù)測(cè),方便測(cè)試。粗暴地級(jí)聯(lián)式刷新視圖使用優(yōu)化。 前言 Redux是一個(gè)非常實(shí)用的狀態(tài)管理庫(kù),對(duì)于大多數(shù)使用React庫(kù)的開(kāi)發(fā)者來(lái)說(shuō),Redux都是會(huì)接觸到的。在使用Redux享受其帶來(lái)的便利的同時(shí), 我們也深受其問(wèn)題的困擾。 redux...

    levius 評(píng)論0 收藏0
  • React+ Redux + React-route + Axios 實(shí)戰(zhàn),很適合進(jìn)階

    摘要:前言前段時(shí)間學(xué)習(xí)完了的基礎(chǔ)自己網(wǎng)上找了一些實(shí)戰(zhàn)項(xiàng)目做了幾個(gè)感覺(jué)項(xiàng)目不是很全面就想做一個(gè)完整的項(xiàng)目來(lái)提升自己的水平以前學(xué)習(xí)的時(shí)候就看過(guò)大神的項(xiàng)目所以自己打算用重寫它后端數(shù)據(jù)還是用實(shí)在沒(méi)有精力擼后端感謝大神該項(xiàng)目是餓了么目前開(kāi)發(fā)了登錄注冊(cè)購(gòu) 前言 前段時(shí)間學(xué)習(xí)完了React的基礎(chǔ),自己網(wǎng)上找了一些實(shí)戰(zhàn)項(xiàng)目,做了幾個(gè)感覺(jué)項(xiàng)目不是很全面,就想做一個(gè)完整的項(xiàng)目來(lái)提升自己的React水平.以前學(xué)習(xí)...

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

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

0條評(píng)論

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