為什么我想要使用redux?
前段時間初步上手了react,最近在使用react的程序中發現對于組件之間通信的需求比較迫切,尤其是在axios異步請求后端資料的時候,這樣的需求是特別強烈的!舉個例子:
// 廠家報告到貨 class ReportArrivalGoods extends React.Component{ constructor(props){ super(props); this.state = { columns:tableHead.ReportArrivalGoods,//這里是初始化的表頭,內容較多,不顯示出來了 data: [] }; }componentDidMount(){ axios( { method: 'get', url: 'http://172.89.1.79/LogisticsSporadicBoardBackEnd/index.asmx/ReportArrivalGoods' }) .then( res => { this.setState( data:NewState ); } ) .catch( error => { console.log(error); } ); }
render(){ return( <Table style={{width: '100%'}} columns={this.state.columns} data=https://www.cnblogs.com/wuhao19950102/p/{this.state.data} border={true} maxHeight={tableMaxHeight} /> ); } }
我們聚焦于下面的componentDidMount()函式
componentDidMount(){ axios( { method: 'get', url: 'http://172.89.1.79/LogisticsSporadicBoardBackEnd/index.asmx/ReportArrivalGoods' }) .then( res => { this.setState( data:NewState ); } ) .catch( error => { console.log(error); } ); }這是大家都很熟悉的react生命周期鉤子函式,我做了這樣一件事:頁面渲染完向后臺請求資料并顯示到頁面上,但是用過axios的都知道,他跟ajax一樣,都是異步的,也就說,你發處請求后就會立即執行后面的代碼了,等你請求結果回來了才會執行then()和catch(),一開始我簡單粗暴的直接把整個函式體寫進了鉤子中,實作是沒問題了,可是要使用鉤子函式請求不同資料的組件有5個,要是每個組件都寫這么一長串代碼,一方面不好看,另一方面重復代碼太多了,于是我想到了把這段函式體封裝起來,于是就有下面的代碼
//webservice資料請求函式 function AxiosGet(desinationURL){ axios( { method: 'get', url: desinationURL }) .then( res => { ); } ) .catch( error => { console.log(error); } ); }
可是要是封裝了怎么設定我組件的state呢?機智的我想到了個辦法,在組件內部創建一個帶參函式modifyState(),在使AxiosGet()函式時將modifyState()函式作為引數傳入AxiosGet()并在AxiosGet()內部將res.data作為引數傳modifyState()從而達到setstate的目的,說起來有點繞,用代碼說話
//webservice資料請求函式 function AxiosGet(desinationURL,ApplyNewState){ axios( { method: 'get', url: desinationURL }) .then( res => { ApplyNewState(res.data); } ) .catch( error => { console.log(error); } ); }
上面是組件外部的資料請求函式,下面的是組件內部的鉤子函式和用于傳入獲取資料的函式
modifyState(NewState){ this.setState( { data:NewState } ); } componentDidMount(){ AxiosGet('http://172.89.1.79/LogisticsSporadicBoardBackEnd/index.asmx/ReportArrivalGoods', this.modifyState ); }
恩,明眼人應該已經看懂了,我巧妙的通過在組件內部將函式傳出的方式完成了state的更新,問題雖然解決了,但是這樣操作著實麻煩,要是能在組件外部更新組件的state就好了,有人要說了,狀態提升啊!為所有的組件創建一個父組件,在父組件中統一更新狀態并通過props的形式傳入子組件,恩,這確實是個辦法,但是父組件就沒有表達出了特別的意思了,就好像div一樣,沒有語意化,有沒有更好的方式呢?百度搜搜react的state,來了來了,他來了,燈燈燈燈!redux閃亮登場!
Redux使用七步走
此處對于redux的知識不做講解了,我懂得也就那樣,redux官網上教程很清晰,可以直接過去學,我主要講講redux在react中的使用,如標題所說,只需要七步,眾所周知,在redux中,最重要的東西就三個
{
動作:action,
動作處理函式:reducer,
狀態倉庫:store
}
想必redux官方教程過了一遍的人都能輕松理清其中關系與具體運行吧,那么問題來了,怎么在react中把組件們的state和store給他系結上呢?網上帖子一大堆,但是跟我之前那篇中說的一樣,抄來抄去,沒有真正講到小白的點子上,有的還抄錯了導致讀者誤解,這里我從小白視角做出最貼切的講解,相信大家聽完手敲一遍也就懂了,我是用create-react-app搭建的開發環境,這里不做贅述,話不多說,上代碼!目錄結構如圖所示:

第一步:安裝依賴:
npm i redux react-redux -s
第二步:創建action
// /actions/test.js export const PLUS='PLUS'; export function plusActionCreator(){ return{ type:PLUS } }
第三步:創建reducer
// /reducers/test.js
import {PLUS} from '../actions/test'
const initState={count:0};
export function plusReducer(state=initState,action){
switch(action.type){
case PLUS:{
return
{
count:state.count+1;//此處回傳的state只是plusReducer這個小范圍內的state,理解這一點很重要!!!
}
}
default:return state;
}
}
第四步:創建store
// /index.js
const reducer=combineReducers({plus:plusReducer});//這里需要傳入json物件才行,物件名代表來自哪個reducer var store=createStore(reducer);
上面是redux部分,大家應該很熟悉了,此時也到了最重要的部分:react和redux的結合,需要說明一下,react的組件我們現在分為展示組件和容器組件兩類,展示組件負責界面呈現,容器組件負責為展示組件管理state,展示組件的所有state通過props傳入,
第五步:創建展示組件
// /index.js function Test (props){ return( <div> <p>總計數:{props.count}</p> <button onClick={props.plus}>加一</button> </div> ); }
第六步:通過react-redux提供的connect方法生成容器組件
// /index.js const CollectionComponent=connect( (state)=>{ return{ count:state.plus.count//這里需要注意,各個小版塊的state是通過combinereducers中命名的json物件名做了分隔的
//此處的json物件count與展示組件中的props.count是對應關系
} }, (dispatch)=>{ return{ plus:bindActionCreators(plusActionCreator,dispatch)
//此處的json物件plus與展示組件中的props.plus方法也是對應關系
} } )(Test);//此處的Test與展示組件名也是對應關系
這里很關鍵,首先const CollectionComponent,這個CollectionComponent就是我們所需要的容器組件,
connect(read,write)(destination)函式有三個引數read、write和destionation(抽象名,為了方便理解這么叫),read的目的就是從store中回傳我們要的state,write的目的是傳入action來更新state,destination用來系結到指定的展示組件,
第七步:通過react-redux提供的Provider組件搭建react和redux資料互動的橋梁
// /index.js
ReactDOM.render( <Provider store={store}>//這里把之前創建的store傳給Provider,這樣store中的state就能傳達到容器組件中了 <CollectionComponent/>//由于第六步忠已經把展示組件系結到了容器組件上了,所以此處只需寫容器組件即可 </Provider> ,document.getElementById('root'));
OVER!通過這個小demo即可完成一個簡單的累加器,最后貼上完整原始碼,嘿嘿嘿,yes!
// /reducers/test.js import {PLUS} from '../actions/test' const initState={count:0}; export function plusReducer(state=initState,action){ switch(action.type){ case PLUS:{ return { count:state.count+1 } } default:return state; } }
// /actions/test.js export const PLUS='PLUS'; export function plusActionCreator(){ return{ type:PLUS } }
// /index.js //react import React from 'react' import ReactDOM from 'react-dom' //redux import {connect,Provider} from 'react-redux' import {bindActionCreators,combineReducers,createStore} from 'redux' import {plusReducer} from './reducers/test' import {plusActionCreator} from './actions/test' //呈現部分 function Test (props){ return( <div> <p>這里是count:{props.count}</p> <button onClick={props.plus}>加一</button> </div> ); } //redux部分 const reducer=combineReducers({plus:plusReducer});//這里需要傳入json物件才行 var store=createStore(reducer); const CollectionComponent=connect( (state)=>{ return{ count:state.plus.count//這里需要注意,各個小版塊的state是 //通過combinereducers中命名的json物件名做了分隔的 } }, (dispatch)=>{ return{ plus:bindActionCreators(plusActionCreator,dispatch) } } )(Test); ReactDOM.render( <Provider store={store}> <CollectionComponent/> </Provider> ,document.getElementById('root'));
最后再給個小彩蛋吧,今天剛搗鼓的react-router的小demo,也是嵌套在上面的代碼中的,
//react import React from 'react' import ReactDOM from 'react-dom' //redux import {connect,Provider} from 'react-redux' import {bindActionCreators,combineReducers,createStore} from 'redux' import {plusReducer} from './reducers/test' import {plusActionCreator} from './actions/test' //router import { BrowserRouter,Switch,Route,NavLink } from 'react-router-dom'; //呈現部分 function Test (props){ return( <div> <p>這里是count:{props.count}</p> <button onClick={props.plus}>加一</button> </div> ); } //redux部分 const reducer=combineReducers({plus:plusReducer});//這里需要傳入json物件才行 var store=createStore(reducer); const CollectionComponent=connect( (state)=>{ return{ count:state.plus.count//這里需要注意,各個小版塊的state是 //通過combinereducers中命名的json物件名做了分隔的 } }, (dispatch)=>{ return{ plus:bindActionCreators(plusActionCreator,dispatch) } } )(Test); ReactDOM.render( <Provider store={store}> <BrowserRouter > <Switch> <Route path="/class/classmates"> <div>QianYingLi,HaoWu,ZhouHuiFan</div> <NavLink to="/class" activeClassName="fillInClassNameHere"> redirect to class </NavLink> </Route> <Route path="/class"> <div>高一二</div> <NavLink to="/class/classmates" activeClassName="hurray"> redirect to classmates </NavLink> </Route> <Route path="/"> <CollectionComponent/> </Route> </Switch> </BrowserRouter > </Provider> ,document.getElementById('root'));
轉載請註明出處,本文鏈接:https://www.uj5u.com/qiye/177552.html
標籤:JavaScript
上一篇:前端的發展和未來趨勢
