從零搭建React+TypeScript的后台項目(三)


本章主要講解redux在React項目中的應用。Redux官方文檔

一、基本概念

Action

action簡單理解就是對象字面量。功能上來說就是把數據從應用傳到store的有效載荷,和Vue中Mutation提交載荷類似。

有action創造函數,是一個生成action的方法。下面就是一個簡單的同步actin:

export function setGlobalState(data: {}) {
    return {type: 'SET_GLOBAL_STATE', data}
}

action生成后,store並沒有生成或者發生變化,只是說明我要更新store了。怎么更新需要通過reducer函數來處理。

Reducer

reducer本質上是純函數,接受oldState、action兩個參數,返回newState。reducer告訴開發系統是怎么更新store的。

function global(state: Global, action: any) {
    switch(action.type) {
        case 'SET_GLOBAL_STATE':
            return action.data
        default:
            return InitGlobalState
    }
}

reducer支持組合和拆分,可以根據項目業務合理進行組織。

Store

store就是項目中的數據流,將action和reducer聯系起來。Redux應用只有一個store,起職責如下:

  • 維持應用的 state;
  • 提供 getState() 方法獲取 state;
  • 提供 dispatch(action) 方法更新 state;
  • 通過 subscribe(listener) 注冊監聽器;
  • 通過 subscribe(listener) 返回的函數注銷監聽器。

下面我們初始化一個store

import { createStore } from 'redux'

// 初始化store
const Store = createStore(
  rootReducer,
)

二、React中使用Redux

 redux是一種狀態管理通用實現方案,可以應用在許多地方,並不受庫的限制。react-redux正是兩者搭配起來實現的通用庫。

yarn add react-redux

Provider全局注入store

然后通過react-redux提供的Provider組件實現store注入。

import Store from './store'
import { Provider } from 'react-redux'

ReactDOM.render(
    <Provider store={Store}>
        <App/>
    </Provider>,
    document.getElementById('root') as HTMLElement  //類型斷言
);

這樣項目中的所有組件都能訪問到store中state,並且通過dispatch來更新state。總之,store在項目中是單獨存在的一個整體,作為數據源存在。而項目外部可以獲取state,改變store中state的唯一方法就是dispatch(action)。

組件中使用store

下面我們一todo.tsx組件為例,介紹組件中是如何獲取、更新state的。

import { connect } from 'react-redux'

const mapStateToProps = (state:InitState) => {
    return {
        todos: state.todos
    }
}
  
const mapDispatchToProps = (dispatch:Dis) => {
    return {
        onAddTodo(value: string) {
            dispatch(addTodo(value))
      }
    }
}

Provider組件將store注入到組件中的本質,還是將store通過組件的props關聯到每個組件上。接下來我們將兩個map函數綁定到組件的屬性上。

interface Props {
    todos: []
    onAddTodo:(value: string) => void 
}
interface State {
    value: string
}

class Todo extends React.Component<Props, State> {    

    constructor(props: Props) {
        super(props)
        this.state = {
            value: ''
        }
    }

    handleAddTodo = () => {
        this.props.onAddTodo(this.state.value)
        this.setState({
            value: ''
        })
    }

    handleInputChange = (e: any) => {
        const { value } = e.target
        this.setState({
            value
        })
    }

    render () {
        return(
            <div>
                <Input value={this.state.value} placeholder="請輸入清單項" onChange={this.handleInputChange}/>
                <Button onClick={this.handleAddTodo}>添加</Button>
                <ul>
                    {this.props.todos.map((todo: any) => (
                        <li>{todo.text}</li>
                    ))}
                </ul>
            </div>
        )
    }
}

export default connect(
    mapStateToProps,
    mapDispatchToProps
)(Todo)

這樣我們就實現了在組件內部獲取state,並且通過界面交互可以動態新增待辦清單,更新store,最后實時渲染頁面的功能。

三、redux高級用法

組合拆分reducer

之前有講到可以拆分reducer,做到單一功能模塊對應一個reducer。類似於Vuex中將store分成多個子modules。

redux提供的combineReducers方法即可接受多個reducer。

import { createStore, combineReducers } from 'redux'
import Todo from './todo/reducers'
import Ware from './ware/reducers'

const rootReducer = combineReducers(
    Object.assign({}, Todo, Ware)
)

然后將rootReducer傳入createStore中即可。

action中間件

中間件MiddleWare可以在我們進行disatch時,更加細粒化的跟蹤store的變化,並且允許我們建立異步action。

下面我們來看react-thunk中間件的作用,使用middleWare后,action創建函數除了返回action對象外,還能返回函數。這個函數會被react-thunk執行,在函數內部能執行更多操作,執行異步請求、dispatch action。

yarn add react-thunk

下面我們來修改下store/index.tsx文件:

import thunkMiddleware from 'redux-thunk'
import { createStore, applyMiddleware, combineReducers } from 'redux'

const Store = createStore(
  rootReducer,
  applyMiddleware(  
    thunkMiddleware,
  )
)

現在我們的action創造函數中就能像下面這樣寫:

export function addTodo(text: string) {
    return { type: 'ADD_TODO', text }
}

export function asyncAddTodo(text: string) {
  return (dispatch:Dis, getState: Get) => {
    if (checkStoreTodo(getState(),text)) {
      // 在 thunk 里 dispatch 另一個 thunk!
      return dispatch(addTodo(text))
    } else {
      // 告訴調用代碼不需要再等待。
      return Promise.resolve()
    }
  }
}

還有react-logger提供的中間件,在本地開發時在進行dispatch時,能打印改動日志。不僅如此,我們還可以自定義middleWare,用來實現自己想要的邏輯效果。

現在redux在react中一些基本用法都介紹完畢了,react中的一些第三方庫基本和TypeScript結合的很好,可能有時候回調函數的參數不知道如何進行類型定義。有個d.ts文件則能在開發時進行智能提示,這個文件主要是在ts文件以js文件發布后,用來標記js文件里面對應的類型。

TypeScript官方文檔有興趣的朋友可以看看。

題外話,redux使用起來有點復雜。安利另外一個狀態管理方案MobX,並且在react得到很好的實現,真正做到了開箱即用,代碼寫到哪里就在哪里使用!

這是一個系列文章:

從零搭建React+TypeScript的后台項目(一)--構建基礎React+TypeScript項目

從零搭建React+TypeScript的后台項目(二)--后台router實現方案

從零搭建React+TypeScript的后台項目(三)--Redux基本配置 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM