过年那会因为毕业设计,第一次接触到React生态,给我留下印象最深的就是Redux了,第一次听到这个概念简直像听天书,看了好几遍官方文档都搞不懂啥东西(ps:(┬_┬)可能是我太菜了),项目也因此卡了好久。后来找到一些Redux的视频,跟着做了几遍才基本理解。
本篇也主要围绕RN项目的Redux进行讲解。
Redux是什么?
Redux 是 JavaScript 状态容器,提供可预测化的状态管理。 ——官方文档
啥玩意?可预测的状态管理?当时就把我看懵逼了,代码怎么可以预测程序状态。后来才知道这个可预测的意思是预先设定好状态容器。
Redux中主要就是以下三个概念
名称 | 作用 |
---|---|
action | action 描述了有事情发生了,通过type区分不同的状态类型,它里面可以放一些状态的数据 |
reducer | reducer做的是响应 action并发送到 store 的,它通过不同的action类型去告诉store改变状态 |
store | store类似于数据库,存储由reducer发送过来的状态(store只能有一个,action和reducer没有限制) |
为什么要使用Redux?
因为React是单向数据流(ps:只能通过props一层一层往里传递),一旦层级过高,父组件和子子孙孙组件通信也太累了吧,于是Redux出现了,它的作用就是隔代传递消息。
如果你不知道是否需要 Redux,那就是不需要它。
过早优化是万恶之源 —— Donald Knuth
在使用Redux前,我们得明确一个事情,就是我们的项目需不需要使用Redux。其实我就是那种杀鸡用牛刀的,小型应用说实话只需要使用原生的页面传值和函数回调就可以实现数据同步,如下面这张图所示(ps:图是偷的,图片出产地)。
随着项目变得复杂,我们项目的有了更多子组件,子组件有有了子组…,情况如下图所示:
看了上面的图我们可以发现一个事情,当一个子组件state变化影响多个组件需要更新视图时候,这个state就需要上升存到共有的父组件中,再一级级往下传,如果一两层还好多一点,真的让人头皮发麻,还会引起一些未知影响,可能你的props值跟别的组件中值名字相同呢!到时候哪里错了都找不到。
那么如果我们使用了Redux后,状态会如何进行传递呢?
如上图所示,当某一个子组件发送状态变化,他就把这个变化的信息发送给Reducer,然后存储在Store,需要这个状态的子组件与Store建立连接就可以获取到这个状态的变化了。
未使用Redux之前,就像你想给远方的朋友A寄一个快递,你找了个熟悉的朋友帮你送过去,你朋友再找朋友。。。最后送到那个远方的朋友A手里。
使用了Redux之后了,就像你现在寄快递找了个快递公司,告诉他地址就好了,不用托关系啊什么的,一步到胃!
Redux怎么使用?
咱要学就学规范的写法! 此处写法我参考了:CrazyCodeBoy大佬的视频 需要资源的童鞋在下方留言,我只有老版本资源,如果有money的童鞋建议自行购买(ps:如果我有钱的话,我也不会白嫖的!真的!)。
注意:以下都是React Native中集成Redux的写法,项目地址
安装Redux依赖
npm install redux --save
npm install react-redux --save
npm install react-thunk --save //可选:这个中间件主要是为了让action内部能够处理一些东西,例如网络请求
创建Store
import {compose ,applyMiddleware, createStore} from 'redux'
import thunk from 'redux-thunk'
import reducers from '../reducer/index'
import { middleware } from '../navigator/AppNavigator'
import action from '../action'
// 中间件是一个数组
const middlewares = [
middleware,
thunk
];
// 这里是为了引入react-native-debugger
const composeEnhancers = window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ || compose;
const store = createStore(
reducers, composeEnhancers(applyMiddleware(...middlewares))
);
// 创建store
export default store;
创建完了,需要在根App中加入Provider并且绑定store
export default class App extends React.Component{
render(){
return (
<Provider store = {store}>
<AppNavigator/>
</Provider>
);
}
};
创建action
// action/index.js
// 根action,导出所有action方法
import {onThemeChangeColor} from './theme'
export default{
onThemeChangeColor,
}
// action/theme/index.js
import Types from '../types'
// 改变主题颜色
export function onThemeChangeColor(themeColor){
return {
type: Types.THEME_CHANGECOLOR,
themeColor: themeColor
}
}
创建reducer,根据action的type修改Store中的状态
// reducer/index.js
import { combineReducers } from 'redux'
import theme from './theme'
// 合并所有的reducer
const index = combineReducers({
theme: theme,
});
export default index;
// reducer/theme/index.js
// 主题相关的reducer
import Types from '../../action/types'
// 设置初始state
const defaultState={
themeColor: '#476'
}
export default function onAction(state = defaultState, action){
switch(action.type){
case Types.THEME_CHANGECOLOR:
return{
...state,
themeColor: action.themeColor
}
default:
return state
}
}
完成上述步骤之后,基本就完成了创建一个状态管理,接下来是怎么使用这个状态。
使用
// 如果需要使用store中的状态,就需要这个函数,将hot添加进this.props.hot
const mapStateToProps = state =>({
hot: state.hot
})
// 如果是需要在这个页面,发出action,则需要这个函数,将action的方法也引入this.props
const mapDispatchToProps = dispatch =>({
onLoadHotData: (storeName, url)=>dispatch(actions.onLoadHotData(storeName, url)),
onLoadMoreHotData:(storeName, pageIndex, dataArray, url, callBack)=>dispatch(
actions.onLoadMoreHotData(storeName, pageIndex, dataArray, url, callBack)
)
})
// 将组件与Store连接
const HotTabPage = connect(mapStateToProps,mapDispatchToProps)(HotTab)
详细的代码请看我码云上的案例吧,这demo集成了React Navigation4.0和Redux
后记
写这篇文章的时候我发现,原来React官方也已经出了这种全局管理状态的API——Context! 那我为什么要去搞什么第三方库啊气绝身亡!
其实这两种方式的原理都差不多,redux性能更好(ps:大佬们都这么说),嗯,安慰一下自己。