Taro ,dva数据流管理方案

499 阅读5分钟
  • 安装方法

    • 按照官方文档的就可以了
  • 程序框架搭建

    • 由于比较熟悉 redux,而官方的状态管理工具也是 redux,最近也尝试在学习 dva,所以采用封装了reduxdva框架
  • dva

  • src目录下新建文件夹 utils -> 创建文件 dva.js 用于创建dva实例的配置

   import { create } from 'dva-core'
   import createLoading from 'dva-loading'
   let app, store, dispatch
 // dva 创建配置方法 createApp 
   function createApp(options?: any) {
     // models 是存储了 dva 的 Model对象的数组
     const { models } = options
     // 创建 dva 实例
     app = create({
       ...options
     })
     /* 使用 dva 中间件 dva-loading 作用是用于创建一个全局的 loading Model
       当应用程序处于异步加载数据时,loading 中间件会持续监听该异步请求的状态,在请求结束之前isloading 都处于 true,请求结束后值该为 false,同时 loading 对象停止监听
       使用这个中间件就可以很好的帮助我们在组件中设置加载数据的提示和现实
     */
     app.use(createLoading({}))
     // @ts-ignore
     
     // 把 models 数组中的数据挂载到 dva 实例上
     if (!global.registered) models.forEach((model) => app.model(model))
     // @ts-ignore
     global.registered = true
     // 实例启动
     app.start()
     
     // 获取 挂载store
     store = app._store
     app.getStore = () => store

     // 挂载 dispatch
     dispatch = store.dispatch
     app.dispatch = dispatch
     return app
   }
   // 返回创建 app实例的方法,以及获取全局 dispatch 的方法
   export default {
     createApp,
     getDispatch() {
       return app.dispatch
     }
   }
复制代码
  • 使用

    • 既然已经对 dva 的配置设定了,那接下来就是使用了
    • 在程序的主入口文件 src/app.js
    •  import '@tarojs/async-await';
       import Taro, { Component, Config } from '@tarojs/taro';
       import { Provider } from '@tarojs/redux';
      
       import Index from './pages/index/index';
       import dva from './utils/dva';
       import models from './models';
      
       import './app.less';
       /* 使用刚刚导出的方法创建 app 实例,
         initialState: 程序初始化状态
         models: 程序中所有的 model数组,
         可以类比 redux 中的 多个 reducer
       */
       const dvaApp = dva.createApp({
         initialState: {},
         models: models
       });
       // 获取 store
       const store = dvaApp.getStore();
      
       class App extends Component {
         /* 小程序配置*/
         config: Config = {
           /* 程序页面配置 */
           pages: ['pages/index/index', 'pages/tab/index'],
           window: {
             backgroundTextStyle: 'light',
             navigationBarBackgroundColor: '#fff',
             navigationBarTitleText: 'WeChat',
             navigationBarTextStyle: 'black'
           },
           /* 底部导航按钮配置*/
           tabBar: {
             list: [
               {
                 pagePath: 'pages/index/index',
                 text: '首页'
               },
               {
                 pagePath: 'pages/tab/index',
                 text: ' 第二页'
               }
             ]
           }
         };
      
         componentDidMount() {}
      
         componentDidShow() {}
      
         componentDidHide() {}
      
         componentDidCatchError() {}
      
         render() {
           return (
             /* 把经由 dva 生成的 store 挂载到应用上*/
             <Provider store={store}>
               <Index />
             </Provider>
           );
         }
       }
      
       Taro.render(<App />, document.getElementById('app'));
      
      复制代码
      
    • 复制代码
      
  • 书写模型 model

  • 从上面的代码可以看到这句 import models from './models';

  • models.js 这个文件导出的是一个包含所有 model 的数组models,提供程序所使用的 models

  import article from './article';
  import category from './category';

  export default [article,category];
复制代码
  • models/article
 import { getArticles } from '../services/api'

 export default {
   // 模型的名称
   namespace: 'article',
   // 模型的包含的状态:=> redux state
   state: {
     data: [],
     error: undefined
   },

   // 所有的 异步effect方法
   effects: {
     // 获取首页数据的方法:getInex
     *getIndex({ payload }, { call, put }) {
       try {
         /* 使用从 api 中导出的 getArticles 方法从服务器中获取数据 
           返回数据格式是
           {
             code:0, 0 => 数据获取成功,1=> 数据获取失败

             data:{
               items[] 一个包含所有文章数据的数组
             } 
           }
         */
         // 使用 call 方法发送异步请求 
         const response = yield call(getArticles)
         // 异步请求成功返回后,使用 put 方法派发类型是 'save'的 action,用于设置 state 的 data
         yield put({ type: 'save', payload: { data: response.data.items } })
       } catch (e) {
         // 异步请求出错,把错误信息使用 put 方法派发类型 'save' 的 action,用于设置 state 的 error
         yield put({type: 'save',payload: {error: e}})
       }
     }
   },
   // reducers:使用不同的方法操作 state => 可以类比原生 redux 中 switch 语句中对 action,state 的操作
   reducers: {
     // save 方法,用于把 payload 设置在 state 上
     save(state, { payload }) {
       return { ...state, ...payload }
     }
   }
 }

复制代码
  • 使用 store

    • 程序的架构已经设置好了,store 也挂载到应用上了,下一步就是使用 store
    • src/pages/index/index.js
       import Taro, { Component, Config } from '@tarojs/taro'
       import { View, Text } from '@tarojs/components'
       import { connect } from '@tarojs/redux'
       import './index.less'
    
       // 使用 dva 提供的 connect 方法,把数据挂载到组件的 props 上
       @connect((store) => {
         /* article 是 article.js  namespace:'article' 的模型 
            loading 是在 dva.js 中使用的 dva-loading 中间件的生成的 loading 模型 
         */
         const { article, loading } = store
         return {
           // 把 article 中所有的 state 结构挂载到 props 上
           ...article,
           // 组件 props 设置 isLoading 属性,属性的值 为 loading 中间件监听 article 模型的getIndex 方法的状态 => 正在加载:true, 加载成功:false
           isLoading: loading.effects['article/ getIndex']
         }
       })
       export default class Index extends Component {
         config: Config = {
           navigationBarTitleText: '博客首页'
         }
    
         componentWillUnmount() {}
         // 类比 react 中的 componentDidMount 上面周期,小程序中使用的是 componentDidShow
         componentDidShow() {
         /* 就像写 react 应用一样,当在组件加载完毕后,异步获取数据
          这里就使用 dva实例提供的 dispatch 方法,派发获取数据的 action
           数据格式与 redux 中的 action 没有区别,唯一要注意的是 type 的值是和是由 namespace +  effects 中具体的方法名组成,表明调用具体的 effects 方法,
           下面这个 type 的含义就是 调用 namespace 为 article,方法名为 getIndex 的方法 
           */
           this.props.dispatch({ type: 'article/getIndex' })
         }
    
         componentDidHide() {}
         // 数据都获取完毕后,使用 render 方法显示数据,剩下的就是具体的业务逻辑书写了
         render() {
           return (
             <View className='index'>
               <View>
                 {this.props.data.map((item: any) => {
                   return <Text key={item._id}>{item.title}</Text>
                 })}
               </View>
               <View>
                 <Text>{item.content}</Text>
               </View>
             </View>
           )
         }
       }
    复制代码
    
  • 以上就是 taro + dva 书写小程序的状态管理搭建与使用了,虽然看起了很简单的样子,昨天晚上我自己一个人上手操作的时候,真是毫无头绪,对于 dva taro 小程序都是第一次接触,遇到很多的坑都是从 github 上下载别人已经完成的demo,对着demo的代码看了又看,改了又改,才把数据的通道打通.

    • 最大的感想就是,一定要下载 codeSpell 插件,检查自己的拼写,我遇到的其中一个坑是由于 article模型中的 effect拼写错了,导致一直没有数据进来,调试了好久,打了好多 log, 终于在 dva.js中把所有的数据都打印出来才发现 article中的 effects拼写错误,实在是不该犯这样低级的错误