ReactNative整理:《ReactNative系列》
内容目录
一、简介
二、Redux
使用场景
三、Redux
组成部分
3.1 Action
3.2 Reducer
3.3 Store
四、React-Redux
介绍
4.1 React-Redux 组件分离思想
4.2 connect 方法
4.3 Provider
五、简单示例
一、简介
- 什么是
Redux
Redux
是 JavaScript 状态容器,提供可预测化的状态管理。对可预测化的个人理解:每个状态都是由action
触发旧state
更新生成新的state
,生成结果可控,并且来源都只有一个 -- store
,所以是可预测的。
- 为什么要用
Redux
通俗来讲:由于多个路由页面或组件之间消息传递或相互状态控制太过繁琐,需要中间页面传递消息,通过props
和state
流经多个组件来实现。这样会使通信出错的概率大增,页面越复杂交互越多,这种情况就越严重,所以需要一个可以统筹全局数据状态的工具,用作接收与分发,这时就需要用到Redux
。
从网上找到张图片,可以形象的表示Redux
的功能。
-
Redux
的三大原则
Redux的使用需要遵循三大原则,这里先简单介绍,下文会详细解释。
1、单一数据源
redux
的数据都存放在store
中,保证数据来源的唯一性,同时更便于应用的数据交互;
2、state是只读状态
action
可以去取state
的值,但是不能直接对state
进行修改;
3、使用纯函数修改state
利用reducer
改变原有的state状态,并生成一个新的state返回
Redux文档:Redux文档地址
二、Redux
使用场景
首先,我们需要明确:Redux
是很有用的框架,但并不是非用不可。
什么场景下可以不用:
- 用户使用方式简单,没有太过复杂的交互(这个就不用多解释了)
- 数据来源单一:比方说,数据都是由父组件传递过来,只在当前组件中使用;或者是从服务端拉取,同样只在当前组件中使用。
- 不需要大量与服务器交互
上面情况都可以不用Redux
,那么与之相反的情况下就需要用到Redux
了。
什么情况下使用:
- 用户使用方式复杂 -- 交互频繁且业务逻辑复杂
- 多个用户之间可以协作
- 与服务器大量交互
- View需要从多个来源获取数据
在多交互多数据源逻辑复杂的情况下,才需要用到Redux
;具体情况要根据自身需求确定。
三、Redux
组成部分
Redux
是由三个重要组成部分协同工作的。包括:action
、reducer
和store
。
3.1 Action
Action
就是一个普通Object。其中type
属性是必须包含的,用来区分action
或表示action
的名字。其余属性可以自行配置。Action
是View发出的通知。View与用户发生交互会引起store
中state
的改变,但是用户不能直接操作state
,只能看到或接触到View层,所以需要在操作View的时候通知state
发生改变,此时就要用到action
。我们可以把action
当成是状态存储器store
中状态更新的触发器。
const kAction_Add = {
type: 'Action_Add',
info: 'Todo_add'
}
如上:Action的名称为Action_Add
,跟随该Action携带的信息为info,值为Todo_add
,将整个对象定义为常量,命名为kAction_Add
。
- View会发送很多种消息,因此就会有很多种Action,或者是同一种Action,但是携带的信息不同。我们不可能都手写成常量,所以就会想到用函数的方式来生成Action,这就是Action Creator。
const kAction_Update = 'kAction_Update';
export function update(info) {
return {
type: kAction_Update,
info
}
}
const updateAction = update('information');
上面例子中:定义常量kAction_Update
代表Action的名称,应用中Action种类比较多的时候可以将常量统一用一个常量JS文件管理,并导出方便引用。声明方法update(info)
,可能没接触过React或JS的同学比较困惑对象中info是什么意思,这里代表的含义是info: info
,前一个info是key
值,后一个info是方法传进来的参数。
- 明白了Action的创建之后,就需要了解Action的发送。
store.dispatch()
是View发出Action的唯一
方式。
import { createStore } from 'redux';
// 这里的 func 是指函数 -- reducer
const store = createStore(func);
store.dispatch({ type: 'kAction_Update', info: 'information'})
结合上面的代码可以写成:
store.dispatch(update('information'));
3.2 Reducer
View发送
action
到store
,引起了state
的改变,使得View发生改变。那么action
是如何链接到store
中状态的,又是如何引起状态改变的?这就用到了reducer
。我们可以将reducer
看作是action
和store
之间的纽带。Reducer
是一个函数,它需要两个参数:一个是默认的state
;另一个是action
。最终经过reducer
处理过后会返回一个新的state
。
import { combineReducers } from 'redux';
import * as Types from '../constants/type';
const initState = {
info: ''
};
function handleAction(state = initState, action) {
switch (action.type) {
case Types.kAction_Update:
return {
...state,
info: 'new' + action.info
};
case Types.kAction_Add:
return {
...state,
todo: 'new' + action.todo
};
default:
return state;
}
}
// handleAction 是一个 Reducer 函数,可以有多个类似handleAction这样的 Reducer 函数,用 combineReducers 整合成一个大的 Reducer
export default combineReducers({
handleAction
});
-
Redux
提供combineReducers
方法,用来将Reducer拆分。可以定义多个Reducer函数,最终用该方法将它们组合成一个大的Reducer。 - 由于
Reducer
是纯函数,函数的返回结果是由action
和state
决定的。正是Reducer
这个特性决定了函数中不能修改state
,只能返回一个全新对象。
Q:什么是纯函数?
A:纯函数是函数式编程的概念,需要满足以下约束条件:
1. 不得改写参数
2. 不能调用系统 I/O 的 API
3. 不能调用Data.now()或Math.random()等不纯的方法,因为每次得到的结果不一样
3.3 Store
-
Store
是存储数据的地方,一个应用只能有一个store
。我们可以把它看成是浮在所有页面之上的一个数据存储容器,不同的组件和页面都可以从这个容器中拿到需要的数据。 - Redux提供
createStore
函数来生成store
。
import { createStore } from 'redux';
import Reducers from '../reducers/commonReducer';
const commonStore = createStore(Reducers);
会接收一个Reducer
作为参数,返回生成的Store
对象。
Store
有以下职责:
-
store.getState()
方法获取state; -
store.dispatch(action)
方法更新state; -
store.subscribe(listener)
注册状态监听器; -
store.subscribe(listener)
返回的函数注销监听器。
-
Store
允许使用store.subscribe
方法设置监听函数,一旦state发生变化,就自动执行这个函数。
import { createStore } from 'redux';
const store = createStore(reducer);
store.subscribe(listener);
store.subscribe
方法返回一个函数,调用这个函数就可以解除监听。
let unsubscribe = store.subscribe(() =>
console.log(store.getState())
);
unsubscribe();
四、React-Redux
介绍
React
和Redux
原本是两个相互独立的框架,为了使用起来更高效更灵活,Redux
官方针对React
封装了一套数据状态管理框架 -- React-Redux
。
4.1 React-Redux 组件分离思想
React-Redux
涉及到容器组件和展示组件分离的思想,在React-Redux
中将组件分为 UI组件 和 容器组件
- UI组件
什么是UI组件?可以理解为只负责页面显示。UI组件有如下特征:
1、只负责UI呈现,不包含任何逻辑处理;
2、没有状态(即不使用this.state
);
3、所有数据都由props
提供;
4、不使用Redux的API。
- 容器组件
容器组件包含以下特征:
1、负责数据处理和业务逻辑;
2、包含内部状态;
3、会使用Redux的API。
可能很多人比较困惑:我们自己写的组件里面也有很多业务逻辑和数据处理,难道要都拆开吗?其实不用,React-Redux
规定,UI组件由用户提供,容器组件由 React-Redux 自动生成。
我们可以理解为用户自己创建的组件都是UI组件,和React-Redux生成的容器组件是互不干扰的,它能提供组件,使整个应用可以访问到Redux Store
。
4.2 connect 方法
React-Redux
提供connect
方法,用于从UI组件生成容器组件;该方法不会改变用户创建的组件,而是返回新的已与 Redux store 连接之后生成的 connect 过的组件。
connect([mapStateToProps], [mapDispatchToProps], [mergeProps], [options])
connect可以有四个参数,但是常用的只有前两个mapStateToProps
,mapDispatchToProps
。
- mapStateToProps(state, [ownProps]): stateProps
mapStateToProps
:从字面意思也可以理解,该函数的作用就是建立从(外部的)state
到UI组件的props
的映射关系。定义该参数,组件就会监听 Redux Store 的数据变化,只要 Store 中对应数据发生变化,就会调用该函数,函数中的对象会与组件的props
合并。如果指定了该回调函数中的第二个参数 ownProps
,则该参数的值为传递到组件的 props
,而且只要组件接收到新的 props
(例如:父组件中参数修改导致当前组件props
变动),mapStateToProps
也会被调用。
const mapStateToProps = (state, ownProps) => {
return {
count: state.counter.count,
imageUrl: state.load.imageUrl === ownProps.imageUrl
}
}
- mapDispatchToProps(dispatch, [ownProps]): dispatchProps
mapDispatchToProps
:是connect
的第二个参数,作用是用来建立UI组件和store.dispatch
之间的映射。如果传递的参数是一个对象,那么每个定义在该对象中的函数都会被当作Action Creator
;
函数写法举例:
/**
* 各个Action可以分开表示
* 需要用到 redux 中的方法 bindActionCreators 将 dipstch 与自定义action绑定到一起
* reduceCount 和 increaseCount 为action对应的属性值,使用时
* 只需要调用 this.props.reduceCount 或 this.props.increaseCount 即可
*/
const mapDispatchToProps = dispatch => ({
reduceCount: bindActionCreators(countReduceAction, dispatch),
increaseCount: bindActionCreators(countIncreaseAction, dispatch)
})
/**
* action统一用 dispatch 发送
* 使用时,调用 this.props.dispatch(自定义action creator)
*/
const mapDispatchToProps = dispatch => ({
dispatch
})
/**
* 将所有action组合成一个大的 action creator 对象
* actions 为组合后的对象属性key
* 使用时,调用 this.props.actions.countReduceAction() 或 this.props.actions.countIncreaseAction()
*/
const mapDispatchToProps = dispatch => ({
actions: bindActionCreators(Object.assign({}, {
countReduceAction,
countIncreaseAction
}, ), dispatch)
})
- mergeProps(stateProps, dispatchProps, ownProps): props
mergeProps
函数会将前两个参数mapStateToProps
和mapDispatchToProps
的执行结果和组件自身的props
传入到该回调函数中,有特殊数据需要处理的可以在该方法里处理,函数的返回结果将会作为props
传递到包装过的组件中,一般情况下可以不用传。
- options
如果指定该参数,可以定制connector的行为。基本不用,想了解的可以去查看redux
文档。
4.3 Provider
可以使组件层级中的所有connect
方法,都能够链接到Redux Store
。一般情况下需要将根组件嵌套在
中才能使用connect
方法。
render() {
return (
);
}
五、简单示例
1、首先创建Action Creators
,将action的标识统一用一个文件管理
import * as Types from '../../constant/types';
export function countReduceAction(count) {
return {
type: Types.kCount_Reduce,
count
}
}
export function countIncreaseAction(count) {
return {
type: Types.kCount_Increase,
count
}
}
2、创建Reducer
,注意需要有初始化数据;多个Reducer
的情况下可以用combineReducers
方法合并成一个大的Reducers。
/**
* 计数reducer
*/
import * as Types from '../../constant/types';
const countInitReduce = {
count: -1
}
export default function handleCount(state = countInitReduce, action) {
switch (action.type) {
case Types.kCount_Reduce:
return {
...state,
count: action.count - 1
};
case Types.kCount_Increase:
return {
...state,
count: action.count + 1
};
default:
return state;
}
}
import { combineReducers } from 'redux';
import handleCount from './countReducer';
import handleLoadImage from './loadImageReducer';
/**
* reducers组合返回
*/
const reducers = combineReducers({
countStore: handleCount,
loadImageStore: handleLoadImage
});
export default reducers;
3、生成Store
,存储全局状态数据
import reducers from '../reducers/baseReducer';
import { createStore } from 'redux';
export function configStore() {
const store = createStore(reducers);
return {
store
};
}
4、用Provider
包裹根组件,并将其connect
到组件中,这样在组件中就可以调用action了。
const mapStateToProps = (state) => ({
count: state.countStore.count,
imageUrl: state.loadImageStore.imageUrl
});
const mapDispatchToProps = dispatch => ({
dispatch
})
export default connect(mapStateToProps, mapDispatchToProps)(HomeClass);
以上就是Redux
和React-Redux
的理解和简单使用,有问题的地方欢迎指出,喜欢的话可以点赞关注。