中文文档
安装
npm install redux react-redux
使用
1、在 src 目录下新建文件 redux/store.js 和 redux/reducer.js 。
2、在 src 目录下新建文件 redux/actions/ActionTypes.js 。
3、在 src 目录下新建文件 redux/reducers/system.js 和 redux/reducers/userInfo.js。(命名随便,你也可以创建其他的 reducers.js 文件)
4、ActionTypes.js
存放ActionTypes常量,避免写在每个reducers里面导致类型重复。
正确格式为 export const CHANGE_USERINFO = 'CHANGE_USERINFO';
为了方便阅读,我把后面改为小写,因为大写常量命名在我看来会造成阅读负担。
// 更新 userInfo
export const CHANGE_USERINFO = 'change_userInfo';
// 重置 userInfo
export const RESET_USERINFO = 'reset_userInfo';
// 更新 system 信息
export const CHANGE_SYSTEM = 'change_system';
// 重置 system 信息
export const RESET_SYSTEM = 'reset_system';
5、system.js
import {CHANGE_SYSTEM, RESET_SYSTEM} from '../actions/ActionTypes';
// 定义状态的默认值
let initialState = {
appName: 'RNDemoApp',
weatherList: [],
};
export const system = (
prevState = {
...initialState,
},
action,
) => {
switch (action.type) {
case CHANGE_SYSTEM:
return {...prevState, ...action.payload};
case RESET_SYSTEM:
return initialState;
default:
return prevState;
}
};
6、 userInfo.js
import {CHANGE_USERINFO, RESET_USERINFO} from '../actions/ActionTypes';
// 定义状态的默认值
let initialState = {
name: 'baidu',
};
export const userInfo = (
prevState = {
...initialState,
},
action,
) => {
switch (action.type) {
case CHANGE_USERINFO:
return action.payload;
case RESET_USERINFO:
return initialState;
default:
return prevState;
}
};
7、 reducer.js
import {combineReducers} from 'redux';
import {system} from './reducers/system';
import {userInfo} from './reducers/userInfo';
const reducer = combineReducers({
system,
userInfo,
});
export default reducer;
8、 store.js
import {legacy_createStore as createStore} from 'redux';
import reducer from './reducer';
const store = createStore(reducer);
export default store;
9、在项目入口文件,我这里是App.js
10、页面的调用与更新
import React from 'react';
import {StyleSheet, View, Text} from 'react-native';
import {connect} from 'react-redux';
import {
commonColors,
commonSize,
commonStyle,
} from 'src/assets/css/commonStyle';
import {SafeAreaView} from 'react-native-safe-area-context';
import {CtBtn, CustomNavbar, HeightSpacer} from 'src/components';
import {
CHANGE_SYSTEM,
CHANGE_USERINFO,
RESET_SYSTEM,
RESET_USERINFO,
} from 'src/redux/actions/ActionTypes';
const ReduxData = props => {
return (
<SafeAreaView style={[commonStyle.container, commonStyle.bgFFF]}>
<CustomNavbar
headerTitle={'redux数据'}
borderColor={commonColors.borderColorLighter}
/>
<HeightSpacer />
<Text>userInfo.name: {props.userInfo.name}</Text>
<HeightSpacer />
<Text>system.appName: {props.system.appName}</Text>
{props.system.version && (
<>
<HeightSpacer />
<Text>system.appName: {props.system.version}</Text>
</>
)}
<HeightSpacer />
<CtBtn
btnText={'更改 userInfo.name'}
width={commonSize.width}
onPress={() => {
props.changeUserInfo({
name: 'chrome',
});
}}
/>
<HeightSpacer />
<CtBtn
btnText={'更改 system.appName'}
width={commonSize.width}
onPress={() => {
props.changeSystem({
appName: 'superApp',
});
}}
/>
<HeightSpacer />
<CtBtn
btnText={'新增 system.version'}
width={commonSize.width}
onPress={() => {
props.changeSystem({
version: '0.0.1',
});
}}
/>
<HeightSpacer />
<CtBtn
btnText={'重置'}
width={commonSize.width}
onPress={() => {
props.resetUserInfo();
props.resetSystem();
}}
/>
</SafeAreaView>
);
};
// 映射 Redux store state 数据到组件中
const mapStateToProps = state => {
return {
userInfo: state.userInfo,
system: state.system,
};
};
// 组件分发 action
const mapDispatchToProps = {
changeUserInfo(data) {
return {
type: CHANGE_USERINFO,
payload: data,
};
},
changeSystem(data) {
return {
type: CHANGE_SYSTEM,
payload: data,
};
},
resetUserInfo(data) {
return {
type: RESET_USERINFO,
};
},
resetSystem(data) {
return {
type: RESET_SYSTEM,
};
},
};
export default connect(mapStateToProps, mapDispatchToProps)(ReduxData);
const styles = StyleSheet.create({});
11、页面展示
12、在没有中间件的情况下,异步获取数据后,分发 dispatch action
获取某地区今明后天气数据
https://devapi.qweather.com/v7/weather/3d?location=116.41,39.92&key=ab016705d280420b8d72f5c6892901dc
网上找的一个接口。。。
试想一下,当接口数据需要放到 store 储存起来的时候,说明该数据在其他页面、组件中也会用到,但是以上面这种方式开发,就不得不把接口请求的部分,复制到其他页面,后续接口有改动就要改很多地方,麻烦且烦琐。
中间件的使用 - redux-thunk
redux只支持同步的action,需要使用一些中间件让 action 返回一个函数,我们在函数中实现异步的操作
安装
npm install redux-thunk
使用
1、改造 store.js
applyMiddleware 可支持多种中间件
import {legacy_createStore as createStore, applyMiddleware} from 'redux';
import reduxThunk from 'redux-thunk';
import reducer from './reducer';
const store = createStore(reducer, applyMiddleware(reduxThunk));
export default store;
2、在 src 目录下新建文件 redux/actionCreator/getWeatherAction.js 。
3、actionCreator/getWeatherAction.js
import {getWeatherApi} from 'src/api/api';
import {CHANGE_SYSTEM} from '../actions/ActionTypes';
export const getWeatherData = () => {
return async dispatch => {
console.log(dispatch);
let resApi = await getWeatherApi({
location: '116.41,39.92',
key: 'ab016705d280420b8d72f5c6892901dc',
});
dispatch({
type: CHANGE_SYSTEM,
payload: {
weatherList: resApi.daily,
},
});
};
};
4、 页面的调用与更新
把异步请求放在 dispatch action 时,此时的api请求也有共享的状态。
getWeatherData方法还可以传递参数,在actions/index.js处理参数进行业务的处理逻辑。
中间件的使用 - redux-promise
阮一峰老师在《Redux 入门教程(二):中间件与异步操作》写到:
既然 Action Creator 可以返回函数,当然也可以返回一个 Promise 对象,这就是 redux-promise 中间件。redux-promise 中间件就是 redux-thunk 与 promise 的结合。
安装
npm install redux-promise
1、修改 store.js
import {legacy_createStore as createStore, applyMiddleware} from 'redux';
import reduxThunk from 'redux-thunk';
import reduxPromise from 'redux-promise';
import reducer from './reducer';
const store = createStore(reducer, applyMiddleware(reduxThunk, reduxPromise));
export default store;
2、 修改 actionCreator/getWeatherAction.js
import {getWeatherApi} from 'src/api/api';
import {CHANGE_SYSTEM} from '../actions/ActionTypes';
// redux-thunk 写法
// export const getWeatherData = () => {
// return async dispatch => {
// console.log(dispatch);
// let resApi = await getWeatherApi({
// location: '116.41,39.92',
// key: 'ab016705d280420b8d72f5c6892901dc',
// });
// dispatch({
// type: CHANGE_SYSTEM,
// payload: {
// weatherList: resApi.daily,
// },
// });
// };
// };
// redux-promise 写法
export const getWeatherData = async () => {
return await getWeatherApi({
location: '116.41,39.92',
key: 'ab016705d280420b8d72f5c6892901dc',
}).then(res => {
return {
type: CHANGE_SYSTEM,
payload: {
weatherList: res.daily,
},
};
});
};
中间件的使用 - redux-saga
目前觉得 redux-saga 比上述两种麻烦,就没有用,但是很多人在推荐 redux-saga。
redux-promise 没有更新了
redux-thunk 每周的下载量比 redux-saga 大,所有暂时先不使用redux-saga了。