---
title: redux 状态管理方案
questions:
  - Smart MiniApp 的 Redux 方案中如何通过 redux-thunk 中间件处理异步 action？
  - 如何在自定义组件中通过 triggerEvent 冒泡机制触发页面级的 Redux action？
  - 页面中如何通过 store.subscribe 监听 state 变化并调用 setData 更新视图？
---

## Redux 状态管理方案

Smart MiniApp 框架提供一套基于 Redux 的状态管理方案，方便管理复杂的业务数据。您可视实际业务场景选择使用。

### 步骤一

安装您所需要的 Redux 的相关包，以及其他您需要的中间件。

```shell
npm i redux --save
npm i redux-thunk --save
npm i redux-logger --save
```

### 步骤二

创建 `store.js`。

```js
import reducer from './reducer/index';
import { createStore, applyMiddleware } from 'redux';
import logger from 'redux-logger';
import thunkMiddleware from 'redux-thunk';

// 创建 redux store
export const store = createStore(
  reducer,
  applyMiddleware(
    logger, // 用于控制台 state 调试
    thunkMiddleware, // 用于处理异步 action
  ),
);
```

### 步骤三

创建 `actions`。

```js
// 这是一个同步的 action
export const INCREASE = 'INCREASE';

export const increase = {
  type: INCREASE,
};

export const addCountAsync = () => {
  return (dispatch) => {
    setTimeout(() => {
      dispatch({ type: 'GET_DATA' });
    }, 2000);
  };
};
```

### 步骤四

创建 `reducer`。

```js
import { combineReducers } from 'redux';

// 这是处理本例子中同步 action 的 reducer
export const disposeIncrease = (state = 0, action) => {
  switch (action.type) {
    case 'INCREASE':
      return state + 1;
    default:
      return state;
  }
};

// 这是处理本例中异步的 reducer
const preState = {};
export const disposeFetch = (state = preState, action) => {
  switch (action.type) {
    case 'GET_DATA':
      return {
        ...state,
        status: 'success',
      };
    default:
      return state;
  }
};

// 按照 state 的结构组合起来
export default combineReducers({
  theIncreasingNo: disposeIncrease,
  asyncData: disposeFetch,
});
```

### 示例代码

#### page1 TYML

```xml

<view class="container">
  <view class="userinfo">
    <button bind:tap="testSyncAction">
      测试同步action，点我加1
    </button>
    <text class="userinfo-nickname">{{number}}</text>
  </view>
  <view class="usermotto">
    <text class="user-motto">{{syncData}}</text>
  </view>
</view>

```

#### page1 js

```js
import { store } from '../../store';
import { increase, addCountAsync } from '../../actions/index';

const { dispatch, subscribe, getState } = store;
Page({
  data: {
    syncData: 'Hello World',
    number: '0',
  },
  onLoad: function () {
    const _this = this;
    subscribe(() => {
      const {
        asyncData: { status },
        theIncreasingNo,
      } = getState();
      _this.setData({
        syncData: `请求状态：${status}`,
        number: theIncreasingNo,
      });
    });
  },

  testSyncAction: function () {
    dispatch(addCountAsync());
    dispatch(increase);
  },
});
```

如果要在自定义组件中触发 `action`，可通过 `triggerEvent` 来执行。

#### customComponent TYML

```xml
<button bind:tap="click">点我触发page action</button>
```

#### customComponent js

```js
Component({
  click: function () {
    this.triggerEvent('xlComponentClick', void 0, {
      bubbles: true,
    });
  },
});
```

#### page1 TYML

```xml
<xlComponent bind:xlComponentClick="testSyncAction"></xlComponent>
```

如在使用过程中遇到任何问题，请联系 涂鸦小程序 团队。
