react native 之 react-redux使用套路
redux是什么?他是一个state容器,这个容器中存放所有页面的state。
redux的运作方式是怎样的?
actions: 可以理解为用户和手机间的交互行为,比如点了一个按钮,下拉刷新,上拉加载更多。。。都可以写成一个action, 一个页面可能会有很多个action。一般action.js中写函数。
页面因为绑定(订阅)了action 和 state,当用户操作界面时,就会触发action中的函数,action 中的函数拉起reducer,处理数据,然后重新render页面。大概机制就是这样。
接入方式:
1. npm install 下列内容:
npm install --save redux npm install --save react-redux npm install --save-dev redux-devtools 当项目中用到了导航栏,就需要这样: npm install --save react-navigation-redux-helpers
(大部分App都用到了导航栏, 所以以下是引入了导航栏的情况)
2. 用<Provider/>包裹根组件, 将store传递给App框架
这里的根组件就是导航组件,要注意AppNavigator/中除了export default connect()之外,还要导出 export const RootNavigator 和 export const rootCom = 'Init'; 后面在合并reducers要用到这两个
import React, {Fragment} from 'react';
import {Provider} from 'react-redux';
import AppNavigator from '../../navigator/AppNavigator'; //此处AppNavigator并未定义 怎么来的呢? 难道是引入默认导出?
import store from './store' //还有此处的store
// import Lamp from './componnets/Lamp' //假如只显示灯一个界面
const App = () => {
return <Provider store={store}>
<AppNavigator/>
</Provider>
};
export default App;
AppNavigator.js代码
import { createStackNavigator, createAppContainer, createBottomTabNavigator, createMaterialTopTabNavigator, createDrawerNavigator, createSwitchNavigator, } from 'react-navigation'; import WelcomePage from '../page/WelcomePage'; import HomePage from '../page/HomePage'; import DetailPage from '../page/DetailPage'; import MainV from '../calendarPages/Main' import NewAct from '../calendarPages/newAct' import NewEdit from '../calendarPages/newEdit' import ActView from '../calendarPages/actView'// import FavoritePage from '../page/FavoritePage';// import ModalExamplePage from '../page/ModalExamplePage'; import AnimationPage from '../page/AnimationPage'; import PanResponderPage from '../page/PanResponderPage';// import MyPage from '../page/MyPage';// import ComponentLifeCyclePage from '../page/ComponentLifeCyclePage';// import JSCallNativePage from '../page/JSCallNativePage';// import NativeCallJSPage from '../page/NativeCallJSPage';// import ChartPage from '../page/ChartPage';// import PromisePage from '../page/PromisePage';// import Lamp from '../page/reduxapp/componnets/Lamp';// import {connect} from 'react-redux'; import {createReactNavigationReduxMiddleware,createReduxContainer} from 'react-navigation-redux-helpers'; export const rootCom = 'Init';//设置根路由 import NaviJumpTransParamsPage from '../page/NaviJumpTransParamsPage'; const InitNavigator = createStackNavigator({ WelcomePage:{ screen:WelcomePage, navigationOptions:{ header:null, } } }); const MainNavigator = createStackNavigator({ HomePage:{ screen:HomePage, navigationOptions:{ header:null, } }, DetailPage:{ screen:DetailPage, navigationOptions:{ //header:null, } }, MainV:{ screen:MainV, navigationOptions:{ //header:null, } }, NewAct:{ screen:NewAct, navigationOptions:{ //header:null, } }, NewEdit:{ screen:NewEdit, navigationOptions:{ //header:null, } },// ActView:{ screen:ActView, navigationOptions:{ //header:null, } },// FavoritePage:{ screen:FavoritePage, navigationOptions:{ //header:null, } }, AnimationPage:{ screen:AnimationPage, navigationOptions:{ //header:null, } }, PanResponderPage:{ screen:PanResponderPage, navigationOptions:{ //header:null, } },// MyPage:{ screen:MyPage, navigationOptions:{ title:'', //header:null, } },// ComponentLifeCyclePage:{ screen:ComponentLifeCyclePage, navigationOptions:{ title:'组件的生命周期', //header:null, } }, JSCallNativePage:{ screen:JSCallNativePage, navigationOptions:{ title:'', //header:null, } }, NativeCallJSPage:{ screen:NativeCallJSPage, navigationOptions:{ title:'', //header:null, } }, NaviJumpTransParamsPage:{ screen:NaviJumpTransParamsPage, }, ModalExamplePage:{ screen:ModalExamplePage, }, ChartPage:{ screen:ChartPage, } , PromisePage:{ screen:PromisePage, }, Lamp:{ screen:Lamp, } }); //连接InitNavigator和MainNavigator // const AppNavi = createSwitchNavigator({ // Init:InitNavigator, // Main:MainNavigator // // },{ // navigationOptions:{ // //header:null, // } // }); // const AppNavigator = createAppContainer(AppNavi); // export default AppNavigator; /////////////////// //连接InitNavigator和MainNavigator export const RootNavigator = createSwitchNavigator({ Init:InitNavigator, Main:MainNavigator },{ navigationOptions:{ //header:null, } }); export const middleware = createReactNavigationReduxMiddleware( state => state.nav, 'root' ); const AppWithNavigationState = createReduxContainer(RootNavigator,'root'); const mapStateToProps = state => ({ state: state.nav, // v2 }); export default connect(mapStateToProps)(AppWithNavigationState);
3. 用connect方法, 包裹导航器组件,导出。connect($1,$2)($3) ,其中$1是state 到props 的映射,$2是dispatch 到props的映射, $3是当前组件。
例如:(这个就是AppNavigator.js代码中最关键的代码)
export const middleware = createReactNavigationReduxMiddleware( state => state.nav, 'root', ); const AppWithNavigationState = createReduxContainer(RootNavigator,'root'); const mapStateToProps = state => ({ state: state.nav, // v2 }); export default connect(mapStateToProps)(AppWithNavigationState);
4. 创建store , 利用createStore()函数,传入reducers 作为参数
import {applyMiddleware,createStore} from 'redux'
import thunk from 'redux-thunk'
import reducers from '../reducers';
import {middleware} from '../../../navigator/AppNavigator'
// 如何自定义中间件
const logger = store => next => action => {
if(typeof action === 'function'){
console.log('dispatch a function',action);
}
else{
console.log('dispatching',action);
}
const result = next(action);
console.log('nextState',store.getState());
}
const middlewares = [
middleware,
logger,
thunk,//暂时没用到
];
export default createStore(reducers,applyMiddleware(...middlewares));
5. 编写action, 一般action的类型集中定义到一个Types文件中, 一个App的action肯定不止一个两个
export const SWITCH = 'SWITCH';
import React, { Component } from 'react';
export function switchLamp(){
return dispatch=>{
dispatch({type:SWITCH})
}
}
6. 编写reducer, 他接收旧的state+action作为参数,然后产生新的state
例如有一个改变App主题色的redecer写法是这样
import {SWITCH} from '../../actions/lamp/index';
const defaultState = {
light : false
};
export default function onAction(state=defaultState,action){
switch(action.type){
case SWITCH:
return {
light:!state.light,
};
default:
return state;
}
}
7. 在页面中使用,从this.props获取状态容器中的数据, 重新渲染页面。这里原理是只要触发了action, 就会更新state,从而更新界面。
用了redux , 页面就不直接导出了,而是通过connect函数导出当前组件。
下面这写代码作用主要是把state绑定到props, 把action绑定到props。这样就能直接在页面用解构赋值取用了。
const mapStateToProps = state =>({
lamp:state.lamp,
});
// 这种写法报错
// function mapDispatchToProps(dispatch) {
// return bindActionCreators(actions.switchLamp, dispatch);
// }
const mapDispatchToProps = (dispatch) => {
return {
switchLamp: bindActionCreators(actions.switchLamp, dispatch)
}
};
// const mapDispatchToProps = dispatch => ({
// switchLamp:() => dispatch(actions.switchLamp),
//
// });
export default connect(mapStateToProps,mapDispatchToProps)(Lamp);
----------------------------------------------分割线----------------------------------------------
后面自己照着做,其间遇到一些小问题,都是步骤不规范引起的。
比如报错:这个就要检查下reducer中关于导航器的写法了
TypeError: Cannot read property 'routes' of undefined This error is located at: in Navigator (at create-redux-container.js:92) in NavigatorReduxWrapper (created by ConnectFunction) in ConnectFunction (at root.js:21) in Provider (at root.js:20) in App (at renderApplication.js:40) in RCTView (at View.js:35) in View (at AppContainer.js:98) in RCTView (at View.js:35) in View (at AppContainer.js:115) in AppContainer (at renderApplication.js:39) getDerivedStateFromProps createNavigator.js:1:1972
应该是这样:
import {combineReducers} from 'redux' import lamp from './lamp' import {rootCom,RootNavigator} from '../../../navigator/AppNavigator'; //1.指定默认state const navState = RootNavigator.router.getStateForAction(RootNavigator.router.getActionForPathAndParams(rootCom)); //2.创建自己的navigation reducer const navReducer = (state = navState,action) => { const nextState = RootNavigator.router.getStateForAction(action,state); return nextState || state; }; //3.合并reducer 因为只允许有一个根reducer const index = combineReducers({ nav:navReducer, lamp:lamp, }); export default index;
严格按照套路来就可以了,特别要注意下结构目录,不然很难调
我测试用的demo: https://github.com/nwgdegitHub/Steward_RN
完整App见: https://github.com/nwgdegitHub/MK_GitHub_App
参考:https://segmentfault.com/q/1010000012086401/a-1020000012111603