redux簡介

Redux 是 JavaScript 狀態容器, 提供可預測化的狀態管理。javascript

那什麼是能夠預測化,個人理解就是根據一個固定的輸入,必然會獲得一個固定的結果。css

redux是專門爲react開發的,但並非只能用於react,能夠用於任何界面庫。html

動機

隨着單頁面應用的普及,web app內部須要管理的狀態愈來愈多,這些狀態可能來自服務器端,用戶輸入的數據,用戶交互數據,當前UI狀態,本地的緩存數據等等。如何可以有條理的管理這些數據,成爲前端開發中一個難題。前端

核心概念

三大原則

單一數據源

使用redux的程序,全部的state都存儲在一個單一的數據源store內部,相似一個巨大的對象樹。java

state是隻讀的

state是隻讀的,能改變state的惟一方式是經過觸發action來修改react

使用純函數執行修改

爲了描述 action 如何改變 state tree , 你須要編寫 reducers。web

reducers是一些純函數,接口當前state和action。只須要根據action,返回對應的state。並且必需要有返回。sql

一個函數的返回結果只依賴於它的參數,而且在執行過程裏面沒有反作用,咱們就把這個函數叫作純函數typescript

基礎

action

顧名思義,action就是動做,也就是經過動做來修改state的值。也是修改store的惟一途徑。express

action本質上就是一個普通js對象,咱們約定這個對象必須有一個字段type,來表示咱們的動做名稱。通常咱們會使用一個常量來表示type對應的值。

此外,咱們還會把但願state變成什麼樣子的對應的值經過action傳進來,那麼這裏action可能會相似這樣子的

{
    type: 'TOGGLE_TODO', index: 5 }

Reducer

Action 只是描述了有事情發生了這件事實,但並無說明要作哪些改變,這正是reducer須要作的事情。

Reducer做爲純函數,內部不建議使用任何有反作用的操做,好比操做外部的變量,任何致使相同輸入但輸出卻不一致的操做。

若是咱們的reducer比較多,比較複雜,咱們不能把全部的邏輯都放到一個reducer裏面去處理,這個時候咱們就須要拆分reducer。

幸虧,redux提供了一個api就是combineReducers Api。

store

store是redux應用的惟一數據源,咱們調用createStore Api建立store。

脫離react的redux案例

store,reducer基礎使用

第一步搭建開發環境,這裏不介紹了,參考上一篇文章 手把手教會使用react開發日曆組件,搭建環境部分

搭建好環境切換到目錄下面

npm install redux --save

把index.tsx修改成之下代碼。

import { createStore, combineReducers, applyMiddleware } from 'redux' var simpleReducer = function(state = {}, action) { return { user: { name: 'redux' } } } var store = createStore(simpleReducer) console.log(store.getState()) 

咱們看到控制檯打印出來的一個包含user信息的這麼一個對象。

咱們使用到了幾個api? createStore建立store,store.getState()獲取store,也就是惟一數據源的根節點。

上文咱們也講過,action的狀況可能會比較多,redux也提供了combineReducers Api。若是咱們有多個reducer,咱們就可使用起來了。

那咱們建立多個reducer測試一下,代碼以下:

import { createStore, combineReducers, applyMiddleware } from 'redux' function user(state = {name: 'redux'}, action) { switch (action.type) { case 'CHANGE_NAME': return { ...state, name: action.name } } return state } function project(state = {name: 'min-react'}, action) { switch (action.type) { case 'CHANGE_NAME': return { ...state, name: action.name } } return state } var rootReducer = combineReducers({ user, project }) var store = createStore(rootReducer) console.log(store.getState())

如咱們所預料同樣,咱們獲得擁有兩個字段的根store。

結合view使用

第一步咱們把html改形成這個樣子,新增了一點標籤

<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Document</title> <style type="text/css"> * { margin: 0; padding: 0; } </style> </head> <body> <div id="userName"></div> <input id="userNameInput"/><button id="userNameButton">更改userName</button> <script src="./dist/main.js"></script> </body> </html>

第二步,修改index.tsx,以下

import { createStore, combineReducers, applyMiddleware } from 'redux' import { func } from 'prop-types' function user(state = {name: 'redux'}, action) { switch (action.type) { case 'CHANGE_USER_NAME': return { ...state, name: action.name } } return state } function project(state = {name: 'min-react'}, action) { switch (action.type) { case 'CHANGE_PROJECT_NAME': return { ...state, name: action.name } } return state } var rootReducer = combineReducers({ user, project }) var store = createStore(rootReducer) function render(state = store.getState()) { var $userName = document.getElementById('userName') $userName.innerHTML = state.user.name } render() console.log(store.getState())

咱們看到頁面正確的顯示了咱們user的名稱。下一步咱們須要作的就是經過用戶的操做,改變store的值,進而觸發view的更新。

因而咱們新增了這塊代碼:

store.subscribe(function() { render() }) // 綁定用戶事件 var $userNameInput = document.getElementById('userNameInput') var userNameButton = document.getElementById('userNameButton') userNameButton.onclick = function() { var value = $userNameInput.value store.dispatch({ type: 'CHANGE_USER_NAME', name: value }) }

咱們看到保存以後,當咱們輸入值以後,點擊更改,頁面的值隨着改變。

可是控制檯報了一個錯誤,TS2339: Property 'value' does not exist on type 'HTMLElement'.,這是因爲typescript強類型校驗沒經過致使的。只要加這段代碼就行了

var $userNameInput = document.getElementById('userNameInput') as HTMLInputElement

看到了吧,redux就是這麼簡單。

其餘全部上層應用,都是在此基礎上開發的,因此開發一個redux應用的步驟就是

  1. 定義action和與之對應的reducer
  2. 監聽store的變化,提供回調函數
  3. dispatch一個action,等待好運發生。

結合react,其餘view類庫,開發步驟莫不如此。

高級應用

異步action

咱們也看到了,咱們的reducer只能作同步應用,若是咱們須要在reducer,作一些延遲操做,可怎麼辦

社區已經有成熟的類庫作這件事件

npm install redux-thunk --save

redux自己已經提升了很好的擴展機制,就是中間件。這點很相似express的中間件。

//引入新的類庫 import { createStore, combineReducers, applyMiddleware, compose } from 'redux' import thunk from 'redux-thunk' ... //store部分作以下修改 const finalCreateStore = compose(applyMiddleware(thunk))(createStore) const store = finalCreateStore(rootReducer, {})

redux-thunk的做用就是讓dispatch方法不只僅只接收action對象,還能夠包含一個方法。咱們能夠在這個方法內部去調用異步代碼

咱們把dom事件部分作了以下改造

userNameButton.onclick = function() { var value = $userNameInput.value store.dispatch<any>(function(dispatch, getState) { setTimeout(() => { dispatch({ type: 'CHANGE_USER_NAME', name: value }) }, 2000) }) }

能夠看到頁面元素確實在2s以後發生了變化,實際業務中啊,咱們這裏能夠作一些異步操做。

至於redux原理,以及源碼和中間件的源碼講解能夠參照個人另一篇文章 閱讀redux源碼

 

 

轉載自:http://www.javashuo.com/article/p-bkepungr-hh.html

相關文章
相關標籤/搜索