就是帮我们统一管理了
- redux
组件的
- react
状态。
- state
统一管理
- redux
呢?没有
- state
我们依旧可以开发 APP,但是当
- redux
的复杂度到达一定程度的时候,摆在我们面前的就是
- APP
的代码(其中包含组件大量的异步回调,数据处理等等),但是使用
- 难以维护
也会增加我们整个项目的复杂度,这就需要我们在两者之间进行权衡了,对于这一部分,
- redux
开发者给我们下面几个参考点:
- redux
:
- redux
:
- redux
适用于 多交互,多数据源,复杂程度高的工程中。
- redux
,
- 某个状态需要共享
等传值比较不容易的情况。就可以考虑
- 需要改变另一个组件状态
,当然还有其他
- redux
的替代产品供我们使用。
- redux
译注:
:被称为下一代客户端与服务端的异步通信方法。取代了单个的 TCP 套接字,使用 ws 或 wss 协议,可用于任意的客户端和服务器程序。WebSocket 目前由 W3C 进行标准化。主要的优点是服务器和客户端可以彼此相互推送信息,允许跨域通信。
- WebSocket
之前,基本的东西还是要都懂的,数据流向介绍:
- redux
的每个动作抽象为一个行为,它有一个必须的参数
- 状态(state)
,定义了
- type
的名称,其他参数可自定义。写法:
- Action(行为)
- {
- type: 'TEST_ACTION',
- key1: 'value',
- ...
- keyN: value
- }
是个对象,所以,我们需要创建这个对象,那创建这个对象的方法叫做
- Action
,写法:
- ActionCreator
- function testAction(key1: ?string, ..., keyN: ?string) {
- return {
- type: "TEST_ACTION",
- key1: key1,
- ...
- keyN: keyN
- }
- }
- function testReducer(state, action) {
- let key1 = action.key1;
- switch(action.type) {
- case TEST_ACTION:
- return {
- ...state,
- key1: key1 + '变化'
- };
- default:
- return state;
- }
- };
- export default testReducer;
- import {
- combineReducers
- }
- from 'redux';
- import testReducer1 from './testReducer1';
- import testReducer2 from './testReducer2';
- export
- default = combineReducers({
- testReducer1,
- testReducer2
- });
- import {
- createStore
- }
- from 'redux';
- const store = createStore(reducers);
- // 获取当前 state
- store.getState()
- // 发送action,根据我们前面 注册的reducers 处理state
- store.dispath(action)
- // 替换当前 state 中的 reducer
- store.replaceReducer(nextReducer)
- // 添加监听
- store.subscribe(listener)
有 5 个 全局方法:
- redux
:创建一个 readux store 来存储应用中所有的 state,应用中只能存在一个 store
- createStore
- createStore(reducer, [initialState],enhancer);
:把多个 reducer 函数作为 value 的 object,合并成一个 reducers 函数,然后就可以通过 reducers 调用各个子 reducer,state 对象的结构由传入的多个 reducer 的 key 决定。
- combineReducers
- combineReducers(...reducers)
:每个 middleware 接受 store 的 dispatch 和 getState 函数作为命名参数,并返回一个函数。
- ...middlewares
:一个应用了 middleware 后的 store enhancer。这个 store enhancer 就是一个函数,并且需要应用到 createStore。它会返回一个应用了 middleware 的新 createStore。
- 返回值
:把 actionCreators 转曾拥有同名 keys 的对象,让 dispatch 把每个 actionCreator 包装起来,这样就可以直接调用它们。唯一使用 bindActionCreators 的场景是需要把 actionCreator 往下传到一个组件上,却不想让这个组件察觉到 redux 的存在,而且不希望把 redux store 或者 dispatch 传给它。
- bindActionCreators
- // actionCreators:一个 actionCreators 或 键值是 actionCreators 的对象
- // dispatch:一个 dispatch 函数, 由 store 提供
- bindActionCreators(actionCreators, dispatch)
:一个与原对象类似的对象,只不过这个对象中的每个函数值都直接 dispatch action。如果传入的是个函数,返回的也是函数。
- 返回值
:当需要多个 store 增强器 依次执行的时候使用它。compose 在应用常见的两个用法:
- compose(...fuctions)
- // 1
- let buildStore = compose(
- applymiddleware(thunk)
- )(createStore)
- // 2
- let initStore = compose(
- applymiddleware(thunk)
- )
的内容(如 redux 数据异步处理等)可前往官方文档阅读查看,这边不讲这么多,只要了解上面的这些就可以了。
- redux
中使用
- react-native
,开发者提供了
- redux
,基础工作原理不变,只不过多了些方法和参数,所以这边就需要继续了解一下,以下内容整理自官方文档:
- react-redux
:使组件层级中的 connect() 方法能够得到 redux store。正常情况下,我们的根组件应该嵌套在
- <Provider store>
注:
之前,我们还是需要配置一下是吧,很简单,我们只需要执行以下步骤:
- redux
打开需要使用
- 终端
的工程主目录:
- redux
- // 比如我们的
- cd Desktop/Test
:
- redux库
- npm install --save redux
,不磨磨唧唧一大堆有的没的,所以我们还需要:
- react-redux
- npm install --save react-redux
,尽量不然这些东西干扰我们。
- 中间件
中 使用
- react-native
了。
- redux
我们可以看出官方建议我们将组件分成
- redux官方文档的示例
、
- containers(容器组件)
、
- components(模块视图组件)
三大块。所以我们这边文件的层级如下图所示:
- redux
与
- action
文件。
- reducer
文件,作为我们的容器组件放到
- Main
文件夹内,
- containers
中的内容:
- Main
- import React,
- {
- Component
- }
- from 'react';
- import {
- StyleSheet,
- Text,
- View,
- TouchableOpacity,
- }
- from 'react-native';
- export
- default class Main extends Component {
- render() {
- return ( < View style = {
- styles.container
- } > {
- /* 需要改变的组件 */
- } {
- /* 按钮 */
- } < TouchableOpacity > <Text > 改变文字按钮 < /Text>
- </TouchableOpacity > </View>
- );
- }
- }
- const styles = StyleSheet.create({
- container: {
- flex: 1,
- justifyContent: 'center',
- alignItems: 'center',
- backgroundColor: '#F5FCFF',
- },
- });/
作为视图组件独立出来,所以将视图组件
- Text
放到
- TestText
文件夹中,
- components
中的内容:
- TestText
- export default class TestText extends Component {
- render() {
- return (
- <Text>Welcome to React Native</Text>
- );
- }
- }
,那前面提到了,我们是要点击按钮的时候让文字发生改变,也就是说我们当前需要一个改变文字的行为,那我们就将这个行为命名为
- action(行为)
, 那么我们需要初始化这个 action 这个对象,也就是前面我们提到的
- CHANGE_TEXT
:
- action creator
- export const CHANGE_TEXT = 'CHANGE_TEXT';
- // 初始化 CHANGE_TEXT 对象
- export const changeText = (text) => {
- return {
- type: CHANGE_TEXT,
- text
- }
- };
文件配置完毕后,我们就可以根据需求来编写
- action
文件了,
- reducer
文件就是起到更新
- reducer
的作用嘛,所以我们将改变 文字 的逻辑放到这里,当
- state
匹配到当前的点击行为为
- reducer
时,就执行相应的操作,返回一个新的
- CHANGE_TEXT
给我们使用,如果匹配不到,那么就默认返回一个不变的新
- state
:
- state
- import {
- CHANGE_TEXT,
- changeText
- }
- from '../action/action';
- const mainReducer = (state = changeText('welcome to React Native'), action) = >{
- const newState = state;
- const text = action.text;
- // 判断 action 类型
- switch (action.type) {
- case CHANGE_TEXT:
- return {...newState,
- text: '改变了' + text
- };
- default:
- return {...newState,
- text: state.text
- }
- }
- };
- export
- default mainReducer;
和
- action
两个文件后,紧接着我们就可以根据
- reducer
来初始化
- reducer
了:
- store
- import Reducer from '../reducer/reducer';
- import {
- createStore
- }
- from 'redux';
- export
- default() = >{
- // 根据 reducer 初始化 store
- const store = createStore(Reducer);
- return store;
- }
的东西已经都配置完成了,接着就剩下使用了,所以接下来要解决的问题就是怎么发送行为,怎么接收
- redux
,上面提到了,
- state(状态)
其实是个方法集,我们的
- store
方法都在
- 发送行为 和 接收状态
中,所以只要拿到
- store
,所以只要拿到
- store
就能进行这两个操作。
- store
呢?在官方文档中,清楚地告诉我们,
- store
的任务就是将
- Provider
传给
- store
,而
- connect
的作用是将我们的组件进行第二次包装,将操作数据的函数和数据的状态包装到
- connect
中,所以,首先,我们需要对我们的
- props
文件进行第一次包装,我们再新建一个
- Main
文件来对
- index
文件进行包装:
- Main
- import React,
- {
- Component
- }
- from 'react';
- // 引用外部文件
- import {
- Provider
- }
- from 'react-redux';
- import Main from './Main';
- import configureStore from '../redux/store/store';
- // 调用 store 文件中的 mainReducer常量中保存的方法
- const store = configureStore();
- export
- default class Root extends Component {
- render() {
- return (
- // 第一层包装,为了让 main 能够拿到 store
- < Provider store = {
- store
- } > <Main / ></Provider>
- )
- }
- }/
文件就可以获得
- Main
了,那接着就是进行第二次包装了,通过
- store
生成新组件:
- connect
- import React,
- {
- Component
- }
- from 'react';
- import {
- StyleSheet,
- Text,
- View,
- TouchableOpacity,
- }
- from 'react-native';
- import {
- connect
- }
- from 'react-redux';
- import {
- changeText
- }
- from '../redux/action/action';
- import TestText from '../components/TestText';
- class Main extends Component {
- render() {
- // 通过 props 拿到保存的 onChangeText
- const {
- onChangeText
- } = this.props;
- return ( < View style = {
- styles.container
- } > {
- /* 需要改变的组件 */
- } < TestText {...this.props
- }
- />
- {/ * 按钮 * /}
- <TouchableOpacity
- onPress={onChangeText}
- >
- <Text>改变文字按钮</Text > </TouchableOpacity>
- </View > );
- }
- }
- const styles = StyleSheet.create({
- container: {
- flex: 1,
- justifyContent: 'center',
- alignItems: 'center',
- backgroundColor: '#F5FCFF',
- },
- });
- // 获取 state 变化
- const mapStateToProps = (state) = >{
- return {
- // 获取 state 变化
- }
- };
- // 发送行为
- const mapDispatchToProps = (dispatch) = >{
- return {
- // 发送行为
- }
- };
- // 进行第二层包装,生成的新组件拥有 接收和发送 数据的能力
- export
- default connect(mapStateToProps, mapDispatchToProps)(Main);
两个方法。首先,我们需要通过
- mapStateToProps(更新回调) 和 mapDispatchToProps(发送行为)
来发送行为,然后通过
- mapDispatchToProps
来监听
- mapStateToProps
的变化,这边我们需要发送的行为
- state
是
- type
, 当发送行为之后,
- CHANGE_TEXT
就会去匹配 行为的类型,进行相应操作:
- reducer
- // 发送行为
- const mapDispatchToProps = (dispatch) => {
- return {
- onChangeText: () => dispatch(changeText('外部传值')),
- }
- };
接收到我们触发的 行为 并进行一系列处理后,最终会返回一个新的
- reducer
,那么 就会自动调用
- state
来告诉系统,
- mapStateToProps
被操作了,那么我们就可以通过
- state
来获取
- mapStateToProps
状态:
- state
- // 获取 state 变化
- const mapStateToProps = (state) => {
- return {
- value: state.text,
- }
- };
中包含了数据获取和操作数据的函数,所以我们需要让 子组件拿到容器组件中的
- props
,然后在 子组件 中通过
- props
就可以拿到上面 定义的
- props
- value 和 onChangeText:
- export
- default class TestText extends Component {
- render() {
- // 获取 props 中的 value
- const {
- value
- } = this.props;
- return (
- // 根据 value 改变内部文字
- < Text > {
- value
- } < /Text>
- );
- }
- }/
小结论:
的项目变得比原本要复杂得多,原本几句代码就能搞定的事情现在要来个
- redux
,这是因为 redux 是为了解决复杂工程而孕育的,所以不要为了使用 redux 而去使用它,使用之前需要权衡一下利弊,其中的好与坏只能自己慢慢体会。
- 山路十八弯
来源: http://www.cnblogs.com/miaomiaoshen/p/6757625.html