安装依赖

执行以下命令安装Redux和依赖包

  1. yarn add react-redux redux dva-core dva redux-logger dva-loading

1、增加store的目录文件

目标=> src/store/index.ts

  1. ├─store // 创建目录
  2. | ├─dva.ts
  3. | ├─index.ts

image.png

往[ src/store/dva.ts ] 添加内容

  1. import { create } from 'dva-core'
  2. import { createLogger } from 'redux-logger'
  3. import createLoading from 'dva-loading'
  4. let app, store, dispatch, registered
  5. function createApp(options?: any) {
  6. const { models } = options
  7. if (process.env.NODE_ENV === 'development') {
  8. // 是否打印redux变化的日志
  9. options.onAction = [createLogger()]
  10. }
  11. app = create({ ...options })
  12. app.use(createLoading({}))
  13. if (!registered) models.forEach((model) => app.model(model))
  14. registered = true
  15. app.start()
  16. store = app._store
  17. app.getStore = () => store
  18. dispatch = store.dispatch
  19. app.dispatch = dispatch
  20. return app
  21. }
  22. export default {
  23. createApp,
  24. getDispatch() {
  25. return app.dispatch
  26. }
  27. }

往[ src/store/index.ts ] 添加内容

引入src/store/dva.ts的文件

  1. import dva from './dva';
  2. const dvaApp = dva.createApp();
  3. const store = dvaApp.getStore();
  4. export default store;

2、创建models文件夹管理数据

目标=> src/models/index.ts

image.png

  1. ├─models // 增加目录models
  2. | ├─app.ts // 使用app为例
  3. | ├─connect.d.ts // 存放公共数据的类型
  4. | ├─index.ts // 作为统一出口

往TS类型文件 [ src/models/connect.d.ts ] 添加内容

  1. import { AnyAction } from 'redux';
  2. import { EffectsCommandMap } from 'dva';
  3. // import { UserModelState } from './user'; 其他model的文件可以导入这里,统一导出
  4. // export { UserModelState };
  5. export interface Loading {
  6. global: boolean;
  7. effects: { [key: string]: boolean | undefined };
  8. models: {
  9. global?: boolean;
  10. menu?: boolean;
  11. setting?: boolean;
  12. user?: boolean;
  13. };
  14. }
  15. export interface ConnectState {
  16. loading: Loading;
  17. // user: UserModelState;
  18. }
  19. export type Effect = (
  20. action: AnyAction,
  21. effects: EffectsCommandMap & { select: <T>(func: (state: ConnectState) => T) => T },
  22. ) => void;
  23. /**
  24. * @type P: Type of payload
  25. * @type C: Type of callback
  26. */
  27. export type Dispatch = <P = any, C = (payload: P) => void>(action: {
  28. type: string;
  29. payload?: P;
  30. callback?: C;
  31. [key: string]: any;
  32. }) => any;
  33. // export interface ConnectProps<T = {}> extends Partial<RouterTypes<Route, T>> {
  34. export interface ConnectProps {
  35. dispatch: Dispatch;
  36. }

往文件 [ src/models/app.ts ] 添加内容

  1. import { Effect } from "dva";
  2. import { Reducer } from "redux";
  3. export interface AppModelState {
  4. name: string // 定义state的变量
  5. }
  6. export interface AppModelType {
  7. namespace: "app"; // 这个名字调用这里的方法的时候需要使用
  8. /**
  9. * 例如:在页面中调用
  10. * useDispatch({
  11. * type: "app/fetchApp"
  12. * })
  13. */
  14. state: AppModelState;
  15. effects: {
  16. fetchApp: Effect;
  17. };
  18. reducers: {
  19. saveApp: Reducer<AppModelState>;
  20. };
  21. }
  22. const initState: AppModelState = {
  23. name: 'nangdie' // 需要管理的公共值
  24. // ...
  25. };
  26. const AppModel: AppModelType = {
  27. namespace: "app",
  28. state: initState,
  29. effects: {
  30. *fetchApp(_, { call, put }) { // 可以异步执行
  31. const result = yield call(/* 放入请求函数,Promise函数 */);
  32. yield put({
  33. type: "saveApp", // 将返回的调用saveApp进行保存
  34. payload: result
  35. });
  36. }
  37. },
  38. reducers: {
  39. saveApp(state = initState, action) { return { ...state, ...action } } // 保存到state上。
  40. }
  41. };
  42. export default AppModel;

往文件 [ src/models/index.ts ] 添加内容

  1. import app from "./app";
  2. // import user from "./user";
  3. // ...
  4. export default [app , /*user*/]; //导出一个数组,里面包含多个模块

3、对所有文件进行关联

将store文件和models文件进行关联

修改 [ src/store/index.ts ] 的内容,导入models

  1. import dva from './dva';
  2. import models from '../models/index'; // 引入models
  3. const dvaApp = dva.createApp({
  4. initialState: {},
  5. models // 加入models , 这是一个数组,可包含多个模块
  6. });
  7. const store = dvaApp.getStore();
  8. export default store;

将 [ src/store/index.ts ]加入到 [ src/app.tsx ]中使用(正式启用)

  • 注意:如果不是app.tsx 需要你把 app.ts 的文件名改成 app.tsx ,然后重新编译即可。 ```typescript import React, { Component } from “react”; import { Provider } from “react-redux”; //新增 import store from “./store/index”; // 新增 import “./app.scss”;

class App extends Component { componentDidMount() { } // render() { return this.props.children } render() { return {this.props.children}; // 新的返回值 } }

export default App;

  1. <a name="OebHt"></a>
  2. ### 4、接下来你可以在组件和页面之间使用了
  3. > 这里可能有人问,为什么不用connect ? 因为connect在Taro有兼容问题,可能导致数据没法更新
  4. <a name="C4TOW"></a>
  5. #### 获取redux中的数据
  6. ```typescript
  7. import { useSelector } from "react-redux";
  8. const appName = useSelector(state => state.app.name);

改变redux中的数据

  1. import { useDispatch } from "react-redux";
  2. const dispatch = useDispatch()
  3. // 调用effects的函数
  4. dispatch({
  5. type: "app/fetchApp",
  6. payload: '新的参数1'
  7. })
  8. // 调用reducers的函数
  9. dispatch({
  10. type: "app/saveApp",
  11. payload: '新的参数2'
  12. })

5、例子:使用redux实现计数

在 [ src/models/app.ts ] 中添加count

  1. import { Effect } from "dva";
  2. import { Reducer } from "redux";
  3. export interface AppModelState {
  4. name: string
  5. count: number //新增
  6. }
  7. export interface AppModelType {
  8. namespace: "app";
  9. state: AppModelState;
  10. effects: {
  11. fetchApp: Effect;
  12. };
  13. reducers: {
  14. saveApp: Reducer<AppModelState>;
  15. saveCount: Reducer<AppModelState>;
  16. };
  17. }
  18. const initState: AppModelState = {
  19. name: 'nangdie',
  20. count: 0 //新增
  21. };
  22. const AppModel: AppModelType = {
  23. namespace: "app",
  24. state: initState,
  25. effects: {
  26. *fetchApp(_, { call, put }) {
  27. const result = yield call(/* 放入请求函数,Promise函数 */);
  28. yield put({
  29. type: "saveApp",
  30. payload: result
  31. });
  32. },
  33. },
  34. reducers: {
  35. saveApp(state = initState, action) { return { ...state, ...action.payload } },
  36. saveCount(state = initState, action) { // 新增方法,将接受到的数字进行保存
  37. console.log(action,'.action')
  38. return {
  39. ...state,
  40. count: action.payload
  41. }
  42. }
  43. }
  44. };
  45. export default AppModel;

修改 [ src/pages/index/index.tsx ]

将该文件下的默认数据清空,修改成Hooks的方式

  1. import React, { Component, useState } from 'react'
  2. import { View, Text } from '@tarojs/components'
  3. import { useSelector, useDispatch } from "react-redux"; //引入
  4. import { AtButton } from 'taro-ui'
  5. const Index = () => {
  6. const count = useSelector(state => state.app.count); // 获取到count
  7. const dispatch = useDispatch()
  8. const addCount = () => {
  9. dispatch({ // 调用方法
  10. type: 'app/saveCount',
  11. payload: count + 1
  12. })
  13. }
  14. return <View>
  15. <View>当前数字: {count}</View>
  16. <AtButton type="primary" onClick={addCount}> 1</AtButton>
  17. </View>
  18. }
  19. export default Index

模拟异步请求数据

只要写在effects里即可
  1. import { showToast, hideLoading } from "@tarojs/taro"; //显示状态
  2. *fetchCount(_, { call, put }) {
  3. // 模拟请求 , 假装我在等待服务器返回结果
  4. const getCount = () => new Promise((resolve) => {
  5. showToast({
  6. title: "请求中...",
  7. mask: true,
  8. icon: "loading"
  9. });
  10. setTimeout(() => {
  11. resolve(new Date().getTime())
  12. hideLoading();
  13. }, 3000);
  14. })
  15. const result = yield call(getCount)
  16. yield put({ // 调用保存
  17. type: "saveCount",
  18. payload: result
  19. })
  20. }

在 [ src/models/app.ts ] 中添加一个方法,完整的代码

  1. import { Effect } from "dva";
  2. import { Reducer } from "redux";
  3. import { showToast, hideLoading } from "@tarojs/taro";
  4. export interface AppModelState {
  5. name: string // 定义state的变量
  6. count: number
  7. }
  8. export interface AppModelType {
  9. namespace: "app"; // 这个名字调用这里的方法的时候需要使用
  10. /**
  11. * 例如:在页面中调用
  12. * useDispatch({
  13. * type: "app/fetchApp"
  14. * })
  15. */
  16. state: AppModelState;
  17. effects: {
  18. fetchApp: Effect;
  19. fetchCount: Effect;
  20. };
  21. reducers: {
  22. saveApp: Reducer<AppModelState>;
  23. saveCount: Reducer<AppModelState>;
  24. };
  25. }
  26. const initState: AppModelState = {
  27. name: 'nangdie',
  28. count: 0
  29. };
  30. const AppModel: AppModelType = {
  31. namespace: "app",
  32. state: initState,
  33. effects: {
  34. *fetchApp(_, { call, put }) {
  35. const result = yield call(/* 放入请求函数,Promise函数 */);
  36. yield put({
  37. type: "saveApp",
  38. payload: result
  39. });
  40. },
  41. *fetchCount(_, { call, put }) {
  42. const getCount = () => new Promise((resolve) => { //模拟请求 , 假装我在等待服务器返回结果
  43. showToast({
  44. title: "请求中...",
  45. mask: true,
  46. icon: "loading"
  47. });
  48. setTimeout(() => {
  49. resolve(new Date().getTime())
  50. hideLoading();
  51. }, 3000);
  52. })
  53. const result = yield call(getCount)
  54. yield put({ // 调用保存
  55. type: "saveCount",
  56. payload: result
  57. })
  58. }
  59. },
  60. reducers: {
  61. saveApp(state = initState, action) { return { ...state, ...action.payload } },
  62. saveCount(state = initState, action) {
  63. console.log(action, '.action')
  64. return {
  65. ...state,
  66. count: action.payload
  67. }
  68. }
  69. }
  70. };
  71. export default AppModel;

在 [ src/pages/index/index.tsx ] 中使用

  1. import React, { Component, useState } from 'react'
  2. import { View, Text } from '@tarojs/components'
  3. import { useSelector, useDispatch } from "react-redux";
  4. import { AtButton } from 'taro-ui'
  5. const Index = () => {
  6. const count = useSelector(state => state.app.count);
  7. const dispatch = useDispatch()
  8. const addCount = () => {
  9. dispatch({
  10. type: 'app/saveCount',
  11. payload: count + 1
  12. })
  13. }
  14. const requestCount = () => {
  15. dispatch({ type: 'app/fetchCount' })
  16. }
  17. return <View>
  18. <View>当前数字: {count}</View>
  19. <AtButton type="primary" onClick={addCount}> 1</AtButton>
  20. <AtButton onClick={requestCount}> 模拟请求</AtButton>
  21. </View>
  22. }
  23. export default Index

最终效果如下


count2.gif