本文从学习的角度,分析整理React Native项目中运用Redux的设计模式。
发现整个项目几乎都是一样的模式,作为原生开发的工程师,理解此模式非常有必要。
注:本文是英文写成,简单加了点中文,将就着看吧。
1. Component(SwitchComponent.js)
- props.data
- props.actions
class Switch extends Component{
constructor(props) {
super(props);
}
render(){
return (
<View style = {style.container}>
<View style = {style.header}>
<View style={style.headerName}>
<Text style={style.headerNameTitle}>Hostname</Text>
<Text style={style.headerNameTitleText}>{this.props.detail.hostname}</Text>
</View>
</View>
</View>
)
}
}
2. Container (SwitchScreen.js)
绑定props和reducer的state
props <===> state
build props to interactive with state
render a Component
import Switch from "../../components/switch/switchComponent";
render(){
const { navigation } = this.props;
return (
<View style={{minHeight:SCREEN_HEIGHT-100}}>
<Switch {...this.props}/> //assign this.props to Switch component
</View>
)
}
以下是绑定三件套
- mapStateToProps
Mapping reducers state to component props(this.props.detail) 建立映射关系
function mapStateToProps(state) {
return {
detail: state.manage.switchDetail.data,
isFetching: state.manage.switchDetail.isFetching,
error:state.manage.switchDetail.error
}
}
- mapDispatchToProps
Mapping Dispatch Actions to component props(this.props.actions) 建立Action映射关系
import manageAction from '../../actions';
function mapDispatchToProps(dispatch){
return {
actions: bindActionCreators(manageAction.device, dispatch)
};
}
- connect
Exported to redux 暴露让redux知道,这里是真正的注册
export default connect(mapStateToProps, mapDispatchToProps)(SwitchScreen);
3. Reducer (switchDetail.js)
Right part(state) of mapStateToProps (state.manage.switchDetail.data)
看看state.manage.switchDetail.data是从哪里来的?
function mapStateToProps(state) {
return {
detail: state.manage.switchDetail.data,
isFetching: state.manage.switchDetail.isFetching,
error:state.manage.switchDetail.error
}
}
入口reducer
App.js (root reducer)
import {Provider} from 'react-redux';
import {createStore, applyMiddleware} from 'redux';
import thunk from 'redux-thunk';
import reducer from './src/reducers';//root reducers
import RootStack from './src/router';
import NavigationService from './src/api/navigationService';
let store = createStore(reducer,applyMiddleware(thunk));
export default class App extends Component {
render() {
console.disableYellowBox = true;
return (
<Provider store={store}>
<RootStack ref={navigatorRef => {
NavigationService.setTopLevelNavigator(navigatorRef);
}} />
</Provider>
);
}
}
import reducer from './src/reducers';//root reducers=>reducers/index.js
import manage from '../features/manage/reducers';
export default combineReducers({
auth,
manage,
form: formReducer
});
=> manage (state.manage)
import switchDetail from './switchDetail';
export default combineReducers({
switchDetail,
portDetail,
});
=>switchDetail (state.manage.switchDetail)
//reducer
const initialState = Immutable({
isFetching: false,
error: false,
data: {},
noRadio:false,
noClients:false,
noWLAN:false
});
export default function switchDetail(state = initialState, action){
switch (action.type) {
case aTypes.LOAD_SWITCH:
return {
...initialState,
isFetching: true,
data: {} //--> state.manage.switchDetail.data
};
case aTypes.LOAD_SWITCH_SUCCESS:
let hasRadio = Object.keys(action.data).length && !!action.data.radios&& action.data.radios.length;
let hasClients = Object.keys(action.data).length && !!action.data.clients&& action.data.clients.length;
let hasWLAN = Object.keys(action.data).length && !!action.data.wlans&& action.data.wlans.length;
return {
...initialState,
isFetching: false,
data: action.data,
noRadio:!hasRadio,
noClients:!hasClients,
noWLAN:!hasWLAN
};
case aTypes.LOAD_SWITCH_FAILURE:
return {
...initialState,
isFetching: false,
error: action.data
};
default:
return state;
}
}
4. Action
Right part(actions) of mapDispatchToProps
看看Actions在哪里注册? manageAction.device
import manageAction from '../../actions';
function mapDispatchToProps(dispatch){
return {
actions: bindActionCreators(manageAction.device, dispatch)
};
}
=>manageAction
import * as deviceAction from './device';
export default {
device: deviceAction
};
=> device.js(actions+dispatch)
Action就是修改数据和状态,dispatch到reducer去处理,reducer返回state给Container去刷新Component或响应事件。
export function retrieveSwithDetail(switch_id) {
return async (dispatch, getState) => {
try {
dispatch({
type: aTypes.LOAD_SWITCH //Loading...
});
// populate dynamic data from tsnData
data["temperature"] = 34;
dispatch({
type: aTypes.LOAD_SWITCH_SUCCESS,//Load succeed
data: data
});
} catch (error) {
dispatch({
type: aTypes.LOAD_SWITCH_FAILURE,//Load failed
data: error
});
}
};
}
=>Reducer(switchDetail.js) handle the dispatch (type+data)
export default function switchDetail(state = initialState, action){
switch (action.type) {
case aTypes.LOAD_SWITCH:
return {
...initialState,
isFetching: true,//Changed the state and make component updated
data: {}
};
case aTypes.LOAD_SWITCH_SUCCESS:
Summary
- Reducer provides state and actions to store data and make component update
- Action returns state with type and data.
- Reducer handles actions and return state(props),state changes make component update.
- Container providers props to component and connect props with reducer state.
- Define Action types as constants.
网友评论