一、前言
react-navtive的状态管理需要使用redux,以下是redux工作的流程图
React组件如果要改变状态,
- 就需要让调用
ActionCreators创建出一个action对象, - 然后再调用store.dispatch(action对象),
- store就会将(previousState,action)传递给Reducers,Reducers处理完成后,就返回newState,
- store再将state更新给React组件
形象化,比喻为我要去图书管借书这件事
ActionCreators创造出一条语句:我要借什么书?- 图书管理员(store)接收了我的请求(dispatch(action对象))
- 图书管理员将请求(previousState,action)输入到电脑的记录本 (Reducers),记录本记录完后,就返回新的的记录本
- 图书管理员(store)于是给了我(React Component)书(state)
二、安装环境
npm install --save redux
npm install --save react-redux
npm install --save-dev redux-devtools
redux(必选)
react-redux(必选)
redux作者为了方便在react上使用redux开发等一个用户react上的redux库redux-devtools(可选)redux开发者工具支持热加载、action重放、自定义UI等功能
三、创建相应的文件
├── store
│ ├── reducer.js
│ ├── actionCreator.js
│ ├── index.js
创建store
// store/inde.js
import {createStore} from "redux"
import reducer from "./reducer"
const store = createStore(reducer)
export default store
创建reducer
// store/reducer.js
const defaultState = {
token:""
}
export default (state=defaultState,action)=>{
if(action.type==="token"){
let newState = {...state}
newState.token=action.value
return newState
}
return state
}
创建constants
// store/constants.js
export const TOKEN = "token"
创建actionCreator
// store/actionCreator
export const setToken =(token){
return {
type:"token",
value:token
}
}
四、组件获取与更改state
获取state
import store from './store/index'
class demo extends Component{
constructor(props){
super(props);
this.state = store.getState()
}
render(){
return (
<View>{this.state.token}</View>
)
}
}
更改state
import {setToken} from "./store/actionCreators"
import store from './store/index'
class demo extends Component{
constructor(props){
super(props)
}
changToken = (token)=>{
const action = setToken(token);// 创建action对象
store.dispatch(action);
}
render(){
return (
<Button
title="设置Token"
onPress={()=>{this.changeToken("abc")}}
/>
)
}
}
五、使用第三方库redux-thunk
原生的redux只能同步处理state,当我们想要异步去处理state时,就没有办法了、比如用户发送登陆请求后,服务器会返回token,此时我们就需要将token保存到state里,网络请求是异步的,于是我们需要使用可以异步更改state的redux-thunk
安装
npm install --save redux-thunk
在创建store时使用redux-thunk中间件
// store/index.js
import { createStore, applyMiddleware } from 'redux';
import thunk from "redux-thunk"
import reducer from "./reducer"
const store = createStore(reducer,applyMiddleware(thunk))
export default store
在actionCreator中创建异步函数
// store/actionCreators
import {login} from "../api/login"//login是登陆的网络请求
export const setToken = (token)=>({
type:"token",
value:token
})
export const Login = ({phone,password})=>{
return dispatch=>{
login({phone,password}).then(res=>{
if(res.code==200){
const action = setToken(res.data)
dispatch(action)
}
})
}
}
在组件中调用异步函数
import {Login} from "../store/actionCreators"
import store from "../store"
class demo extends Component {
render(){
return <View onClick={this.handleLogin}>登陆</View>
}
handLogin=()=>{
const action = Login({phone:1234,password:1234})
store.dispatch(action)// 当store发现action时一个函数时,会先执行这个函数
}
}
六、视图组件绑定
<Provider>组件:这个组件需要包裹在整个组件树的最外层。这个组件让跟组件的所有子孙组件能够轻松的使用connect()方法绑定storeconnect():这是react-redux提供的一个方法,如果一个组件想要响应状态的变化,就把自己作为参数传给connect()的结果,connect()方法会处理与store绑定的细节,并通过selector确定该绑定store中哪一部分的数据selector:这是你自己编写的一个函数,这个函数声明了你的组件需要整个store中的哪一部分数据作为自己的propsdispatch:每当你想要改变应用中的状态时,你就要dispatch一个action,这也是唯一改变状态的方法
react-redux提供以下API
- Provider
- connect
Provider
为了在全局都能使用conect(),必须将根组件嵌套在<Provider></Provider>中
import {Provider} from "react-redux"
import store from "./store"
function App(){
return(
<Provider store={store}>
<AppIndex></AppIndex>
</Provider>
)
}
connect
API原型:
connect([mapStateToProps],[mapDispatchToProps],[mergeProps],[options])
react-redux提供了connect函数,connect是一个高阶函数,首先传入mapStateToProps、mapDispatchToProps,然后返回一个生产Component的函数wrapWithConnect,然后再将真正的Component作为参数传入wrapWithConnect(MyComponent),这样就生产出一个经过包裹的Connect 组件:
如:export default connect(mapStateToProps)(HomePage)
在组件中使用connect
import {connect} from "react-redux"
import actionCreators from "../store/actionCreators"
class deom extends Component{
render(){
reuturn (
<View>token:{this.props.token}</View>
<View onClick={this.props.Login({phone:1234,password:1234})}>登陆</View>
)
}
}
const mapStateToProps = state=>{
return {
token:state.token
}
}
const mapDispatchToProps = dispatch=>{
return {
Login({phone,password}){
const action = actionCreators.Login({phone,password})
dispatch(action)
}
}
}
export default connect(mapStateToProps,mapDispatchToProps)(demo)
mapStateToProps是将store中state映射到组件的props中去,即可以通过this.props.to ken获取到store中的存储的token
mapDispatchToProps返回的是一个对象,这个对象里有许多方法,这些方法里可以调用 dispatch,然后这些方法全部都映射到组件的props中去,既可以通过this.props.方法调用
七、使用actionTypes
action对象一般都是如下:
{
type:"token",
value:"1432"
}
在reducer中,这样判断action的type
export default function (state=defaultState,action){
if(action.type==="token"){
....
}
}
从上面我们可以看到,type都是一个字符串类型,我们在开发过程中,字符串写错了,程序会运行错误,但系统不会报错,为了解决这个问题,我们可以将字符串变成变量
可以在store文件夹下新建actionTypes来存储type类型
├── store
│ ├── reducer.js
│ ├── actionTypes.js
│ ├── actionCreator.js
│ ├── index.js
// store/actionTypes
export const TOKEN = "token"
// store/actionCreator
import * as actionTypes from "./actionTypes"
export const setToken = (token)=>({
type:actionTypes.TOKEN,
value:token,
})
// store/reducer
import * as actionTypes from "./actionTypes"
export default (state=defaultState,action)=>{
if(action.type===actionTypes.TOKEN)
}
这样,当我们变量名写错时,系统就会给予警告
八、使用combineReducers
一个app可能有用户信息,历史消息,设备信息等等,如果我们把所有信息都放在一个reducer中就显得太臃肿不好管理,所以我们可以使用redux提供的combineReducers来合并多个reducer
// store/reducer
import {combineReducers} from "redux"
import {reducer as UserReducer} from "../page/UserLogin/store"
import {reducer as DeviceReducer} from "../page/Device/store"
export default combineReducers({
user:UserReducer,
device:DeviceReducer
})
在组件中可以这样使用
mapStateToProps=(state)=>{
return {
token:state.user.token,
deviceNum:state.device.number
}
}
结语
赠人玫瑰,手有余香。各位看官,觉得不错请点个赞,如有错漏处,还请指正呀
作者:胡志武
时间:2020/02/13