React相關知識點:關於Redux

爲何用Redux

一些小型項目,只使用 React 徹底夠用了,數據管理使用props、state便可,那何時須要引入Redux呢? 當渲染一個組件的數據是經過props從父組件中獲取時,一般狀況下是A –> B,但隨着業務複雜度的增長,有多是這樣的:A –> B –> C –> D –> E,E須要的數據須要從A那裏經過props傳遞過來,以及對應的E –> A逆向傳遞callback。組件BCD是不須要這些數據的,可是又必須經由它們來傳遞,這樣不太友好,並且傳遞的props以及callback對BCD組件的複用也會形成影響。或者兄弟組件之間想要共享某些數據,也不是很方便傳遞、獲取等。諸如此類的狀況,就有必要引入Redux`了。

注:其實 A --> B --> C --> D --> E 這種狀況,React不使用props層層傳遞也是能拿到數據的,使用Context便可。javascript

Redux 的三大基本原則

redux的核心概念就是store、action、reducer

約法三章

State 是隻讀的 react文檔中說唯一改變 state 的方法就是觸發 action,奇怪的是 咱們說State是隻讀的,可是爲啥如今又說能夠修改了呢,其實咱們並非直接修改state,action」是用來向 store 表示要修改 state 的載體。因此咱們並無直接設置state的方法,使用了dispatch(action) 發送 action 至 store 是惟一改變 state 的方式

store

  1. UI惟一數據來源;
  2. 維持應用的 state; 
  3. 提供 getState() 方法獲取 state; 
  4. 提供 dispatch(action) 方法更新 state; 
  5. 經過 subscribe(listener) 註冊監聽器; 經過 subscribe(listener) 返回的函數註銷監聽器。


action

必須擁有type屬性,用來描述發生什麼,action經過reducer處理生成newState後纔可以更改store信息。可是爲了更好的語義編程,Redux經過語句store.dispatch(action)來更新store,reducer對action的處理在內部處理。
java

reducer

僅僅只是根據action.type處理一下須要更新的state
react

建立目錄


建立Store模塊 數據源

//store/index.js編程

/*引入createStore 是用來建立一個數據源對象保存咱們的數據的*/

import { createStore, applyMiddleware, compose } from 'redux';
import { createLogger } from 'redux-logger';
//引用數據源
// store是引用的reducer
// action會觸發reducer
import allreducers from './reducers/index';
//數據處理後會返回給數據源 才能取到最新的數據  在根組件index裏獲取


const logger = createLogger();
const store = createStore(
    allreducers,
    applyMiddleware(logger)
)
console.log(store)
function listerner () {
    store.getState();
}
store.subscribe(listerner);

export default store;複製代碼


傳入Store

Store保存了整個應用的單一狀態樹,全部容器組件都須要從store中讀取,咱們能夠store做爲屬性傳遞給每一個組件,子組件經過props獲取,可是若是嵌套過深,寫起來會很麻煩。還好,react-redux提供一個叫provider的組件,他可讓全部組件均可以訪問到store(他的實現原理其實是利用了react的context功能),而沒必要顯示的一層層傳遞了。
import { Provider } from 'react-redux'
import store from './store';


ReactDOM.render(
   <Provider store={store}> <BrowserRouter> {routes } </BrowserRouter> </Provider>,
    document.getElementById('app')
);複製代碼

建立Reducer 處理業務數據

//reducers/index.jsredux

import * as Types from 'src/store/constants'
import { combineReducers } from 'redux';

const initState = {
    isLogin: "未登陸",
    themecolor: "red",
    count: 0
}


const loginReducer = (state = initState.isLogin ,action) => {
    switch (action.type) {
        case Types.LOGIN_TYPE:
            return state = action.isLogin
        default:
            return state
    }
}

const themeReducer = (state = initState.themecolor ,action) => {
    switch (action.type) {
        case Types.THEME_TYPE:
            return state = action.themecolor
        default:
            return state
    }
}

const counterReducer = (state = initState.count, action) => {
    switch(action.type) {
        case Types.ADD_TYPE: return state + 1;
        default: return state;
    }
}

export default combineReducers({
    isLogin:loginReducer,
    themecolor:themeReducer,
    count:counterReducer
})複製代碼

注意:combineReducers() 函數的做用是把多個 reducer 合併成一個最終的 reducer 函數。
bash

常量統一保存

//constants/index.jsapp

/*常量統一保存,便於管理*/
export const LOGIN_TYPE = "LOGIN_TYPE"
export const THEME_TYPE = "THEME_TYPE"
export const ADD_TYPE = "ADD_TYPE"複製代碼

建立Action模塊

actions/index.jside

import * as Types from 'src/store/constants'
export const loginAction = function(isLogin) {
    return {
        type: Types.LOGIN_TYPE,
        isLogin
    }
}

export const themeAction = function(themecolor) {
    return {
        type: Types.THEME_TYPE,
        themecolor
    }
}

export const addAction = () => {
    return {
        type: Types.ADD_TYPE
    }
}複製代碼

組件調用函數式編程

import React, {PureComponent} from "react"
import store from 'src/store'
import { loginAction,themeAction,addAction } from 'src/store/actions'

const counterfn = () => {
    document.getElementById("counter").innerHTML = store.getState().count
}
store.subscribe(counterfn);
class NwdLogin extends React.Component {
    constructor(props){
        super(props)
    }
    componentDidMount() {
    }
    render () {
        var state = store.getState();
        return (
            <div> <div id="counter"></div> <div> <button onClick={() => store.dispatch(addAction())}>add </button> </div> </div>
        )
    }
}
export default NwdLogin複製代碼



函數

注意:在不使用react-redux的狀況下 必須使用store.subscribe(listener), store更新後回調listener,回調函數裏面能夠調用store.getStore()來獲取更新後得state喲~

結合 react-redux使用

react-redux,redux和react的橋樑工具。 react-redux將組建分紅了兩大類,UI組建component和容器組件container。 

UI組件:

  1. 只負責 UI 的呈現,
  2. 不帶有任何業務邏輯 沒有狀態(即不使用this.state這個變量) 
  3. 全部數據都由參數(this.props)提供 不
  4. 使用任何 Redux 的 AP

容器組件:

  1. 負責管理數據和業務邏輯,不負責 UI 的呈現 
  2. 帶有內部狀態 
  3. 使用 Redux 的 API

1)經過connect方法將React組件和Redux鏈接起來,react-redux 中引入了 connect

import React, {PureComponent} from "react"
import { connect } from 'react-redux'
import { loginAction,themeAction,addAction } from 'src/store/actions'
class NwdLogin extends React.Component {
    constructor(props){
        super(props)
    }
    componentDidMount() {
    }
    render () {
        console.log(this.props)
        return (
            <div> {this.props.isLogin} <button onClick={() => this.props.loginAction("已登陸")}>設置登陸狀態</button> <button style={{backgroundColor:this.props.themecolor}} onClick={() => this.props.themeAction("#fff")}>設置themecolor狀態{this.props.themecolor}</button> </div>
        )
    }
}
const mapStateToProps = (state,ownProps) => {
    return {
        isLogin: state.isLogin,
        themecolor: state.themecolor
    }
}

const mapDispatchToProps = ((dispatch,ownPorps) => {
    return {
        loginAction: (isLogin) => dispatch({
            type: "LOGIN_TYPE",
            isLogin: isLogin
        }),
        themeAction: (themecolor) => dispatch({
            type: "THEME_TYPE",
            themecolor: themecolor
        })
    }
})

export default connect(mapStateToProps,mapDispatchToProps)(NwdLogin)複製代碼





1)connect()() 其實這兒是兩次函數調用。首先。connect() 返回了一個函數,而後咱們馬上調用了這個函數並給它傳遞進第二個括號內的參數。第二個參數通常是一個 React 組件這是一種常見的「函數式編程」的寫法。

2)connect() 的第一個參數是個返回了一個對象的函數 mapStateToProps,這個對象的屬性將會變成 React 組件中的「props」的屬性,你能夠看到他們的值來自 store 的 state。這裏我把這第一個參數命名爲「mapStateToProps」,如命名所示,是但願它來將全局 states 轉化成本地 component 的 props。 mapStateToProps() 將會接收到一個攜帶着完整的 Redux store 的參數 store,而後抽出本地組件須要的 states 轉換成 props。

3)

若是不寫mapDispatchToProps,只能本身手動調用this.props.dispatch()

import React, {PureComponent} from "react"
import { connect } from 'react-redux'
import { loginAction,themeAction,addAction } from 'src/store/actions'
class NwdLogin extends React.Component {
    constructor(props){
        super(props)
    }
    componentDidMount() {
    }
    render () {
        console.log(this.props)
        return (
            <div> {this.props.isLogin} <button onClick={() => this.props.dispatch(loginAction("已登陸"))}>設置登陸狀態</button> <button style={{backgroundColor:this.props.themecolor}} onClick={() => this.props.dispatch(themeAction("#fff"))}>設置themecolor狀態{this.props.themecolor}</button> </div>
        )
    }
}
const mapStateToProps = (state,ownProps) => {
    return {
        isLogin: state.isLogin,
        themecolor: state.themecolor
    }
}

/*const mapDispatchToProps = ((dispatch,ownPorps) => { return { loginAction: (isLogin) => dispatch({ type: "LOGIN_TYPE", isLogin: isLogin }), themeAction: (themecolor) => dispatch({ type: "THEME_TYPE", themecolor: themecolor }) } })*/

export default connect(mapStateToProps)(NwdLogin)複製代碼

react-redux中connect的裝飾器用法@connect

import React, {PureComponent} from "react"
import { connect } from 'react-redux'
import { loginAction,themeAction,addAction } from 'src/store/actions'

@connect(
    state => {
        return {
            isLogin: state.isLogin,
            themecolor: state.themecolor
        }
    },
    {
        loginAction,
        themeAction,
        addAction
    }
)
class NwdLogin extends React.Component {
    constructor(props){
        super(props)
    }
    componentDidMount() {
    }
    render () {
        console.log(this.props)
        return (
            <div> {this.props.isLogin} <button onClick={() => this.props.loginAction("已登陸")}>設置登陸狀態</button> <button style={{backgroundColor:this.props.themecolor}} onClick={() => this.props.themeAction("#fff")}>設置themecolor狀態{this.props.themecolor}</button> </div>
        )
    }
}
export default NwdLogin
複製代碼

redux的bindActionCreators

bindActionCreators是redux的一個API,做用是將單個或多個ActionCreator轉化爲dispatch(action)的函數集合形式。 開發者不用再手動dispatch(actionCreator(type)),而是能夠直接調用方法。


import React, {PureComponent} from "react"
import { bindActionCreators } from 'redux'
import { connect } from 'react-redux'
import { loginAction,themeAction,addAction } from 'src/store/actions'

@connect(
    state => {
        return {
            isLogin: state.isLogin,
            themecolor: state.themecolor
        }
    },
    dispatch => bindActionCreators({loginAction,themeAction,addAction},dispatch)
)
class NwdLogin extends React.Component {
    constructor(props){
        super(props)
    }
    componentDidMount() {
    }
    render () {
        console.log(this.props)
        return (
            <div>
                    {this.props.isLogin}
                    <button onClick={() => this.props.loginAction("已登陸")}>設置登陸狀態</button>
                    <button style={{backgroundColor:this.props.themecolor}} onClick={() => this.props.themeAction("#fff")}>設置themecolor狀態{this.props.themecolor}</button>
            </div>
        )
    }
}
export default NwdLogin

複製代碼
相關文章
相關標籤/搜索