dva-loading 实践用法

作者: dkvirus | 来源:发表于2017-10-16 11:11 被阅读2369次

    dva 中页面过渡效果封装的很好,下面介绍常用的两个 js 库。

    之前对 dva-loading 理解存在误区,认为只要在 index.js 中配置一下就没事了,事实上 dva-loading 只是提供当前异步加载方法的状态(异步加载中状态为 true,异步加载完成状态为 false),对应加载样式由各自组件自己控制,如:Antd 中 Table 组件自身的 loading 属性。并添加完整流程示例代码。

    一、过渡组件 dva-loading

    传统做法

    比如请求一个用户页面,刚进去的时候由于要去服务器请求数据需要花费时间,这段时间页面应该是不能点击的状态。

    如果不使用这个组件,传统做法是写个蒙版组件,提供两个方法 start() 和 end(),当进行 ajax 请求开始时调用 start() 方法给整个页面加上一层蒙版,此时不能进行操作,在请求结束也就是 ajax 的 success 回调函数中调用 end() 方法关闭蒙版,表明数据已经请求到了,可以操作页面。

    作用

    该组件有两处亮点:

    • 一次配置,其它自动。只需简单配置,无需手动写蒙版组件,无需关心什么时候开始请求数据调用 start(),什么时候数据请求完毕调用 end();
    • 在请求数据期间会产生一层蒙版,此时无法操作页面;

    配置

    dva 项目的 index.js 文件:

    import createLoading from 'dva-loading';
    
    const app = dva();
    
    app.use(createLoading());
    

    配置完成后,在任何一个 dva 的 routes 组件中就都会有一个 loading 对象,如果你对 dva 稍有了解的话,应该不难知道它在哪。比如下面这行代码中的 loading 对象就是由于上面的配置。

    export default connect(({ app, loading }) => ({ app, loading }))(App);
    

    打印一下 loading 对象,可看到内容如下:

    loading: {
      global: false,
      models: {app: false},
      effects: {app: false}
    }
    

    我们只需要关注 loading.global 属性,当页面处于异步加载状态时该值为 true,当页面加载完成时,自动监听该值为 false。

    怎么用?

    使用 Antd 的 Table 组件 时,查阅 API 可以看到有个 loading 的属性。如果该属性值为 true,Table 组件自身会显示加载效果,该值为 false,加载效果消失。可以通过 loading 对象判断当前是否有异步加载。具体示例代码如下:

    // src > models >user.js
    export default {
      namespace: 'user',
      state: {
        userList: [],      // 存放用户列表
      },
      effects: {
        * query ({ payload = {} }, { call, put }) {
          // 获取用户列表,赋值给 userList
          // 使用 axios 或者 ajax 请求后台返回数据
          const result = axios.request('xxx/xxx');
          // 调用 reducers 中的 updateState 方法改变 state 中 userList 的值
          yield put({ type: 'updateState', payload: { userList: result.data });
        }
      },
      reducers: {
        updateState (state, { payload }) {
          return { ...state, ...payload };
        },
      },
    }
    
    // src > routes > user.js
    import React from 'react';
    import { connect } from 'dva';
    import { Table } from 'antd';
    
    const User = ({ dispatch, user, loading }) => {
      console.log(loading)  
      /**
        控制台打印值:
        loading: {
          global: true,
          effects: { 'user/query': true },
          models: { 'user/query', true },
        }
        'user/query' 是个异步请求后台的方法,在请求过程中,global 和 effects 中值都为 true,
        当请求结束,已经有数据返回,userList 中获取到用户列表时该值为 false。
        可能有个疑问:既然 global 可以展示异步加载是否完成,为什么还要 effects 属性,这是因为一个页面中
        可能同时有多个异步加载,只要有一个异步加载没有完成,global 都是 true,但是 effects 中加载完成的
        异步方法都会变成 false,只有没加载完成的异步方法也会是 true,毕竟实际业务场景可能会复杂点。
      */
      
      /** 
        根据 loading.effects 对象判断当前异步加载是否完成,并将该值传递给 Table 组件的 loading 属性,
        Table 组件会自己控制加载样式。dva-loading 在这里的作用只是提供异步加载的状态,
        具体加载样式由对应组件自己提供。
      */
      const isLoading = loading.effects['user/query']
      const { userList } = user
    
      return (
        <Table
          dataSource={userList}
          loading={isLoading}
          rowKey={record => record.id}
        />
      );
    }
    
    export default connect(({ user, loading }) => ({ user, loading }))(User);
    

    注:如果还有疑问,可下方留言。

    二、动画组件 nprogress

    安装

    $ npm install nprogress 
    

    作用

    制作页面加载时动态页面,在页面顶端提供动态进度条,表明当前页面正在加载状态。

    nprogress

    用法

    xx.js 中

    import NProgress from 'nprogress';
    

    提供了两个方法:NProgress.start() 和 NProgress.done()。

    在刚开始请求(可以认为是 ajax 请求)页面数据时调用 NProgress.start() 方法,此时页面顶端会有蓝色动态进度条;在页面请求数据完毕时(可以认为是 ajax 的 success 回调函数),调用 NProgress.done() 方法,此时蓝色进度条会瞬间加载 100% 然后消失。

    三、dva-loading 和 nprogress 配合使用

    index.js

    import createLoading from 'dva-loading';
    
    const app = dva();
    
    app.use(createLoading());
    

    app.js

    import React from 'react';
    import { connect } from 'dva';
    import NProgress from 'nprogress';
    
    const App= ({ app, loading }) => {
    
        let currHref = '';
        const href = window.location.href;    // 浏览器地址栏中地址
        if (currHref !== href) {  // currHref 和 href 不一致时说明进行了页面跳转
            NProgress.start();    // 页面开始加载时调用 start 方法
            if (!loading.global) {  // loading.global 为 false 时表示加载完毕
                NProgress.done();  // 页面请求完毕时调用 done 方法
                currHref = href;   // 将新页面的 href 值赋值给 currHref
            }
        }
            
    }
    
    export default withRouter(connect(({ app, loading }) => ({ app, loading }))(App));
    

    相关文章

      网友评论

      • 月肃生:为啥nprogress没反应?
        月肃生:知道了,还得引入import "nprogress/nprogress.css"
      • 28031a197845:我的dva目录没有你说的app.js啊啊啊啊 好烦
        dkvirus:@白开水_7082 不是,app.js 单纯只是个页面,这个页面里有表格,当页面加载完成时自动加载(componentDidMount())表格数据。我这么写的目的是当切换到 app.js 对应的页面自动加载表格数据时,出现过度动画(NProgress.start();),当表格数据加载完成后(怎么知道数据加载完了,通过 loading.global 判断的),取消过度动画(NProgress.done();)。如果你还不明白。可以在你的github提供demo代码,我可以给你调试。
        28031a197845:@dkvirus 我也想做一下加载的动画呀,结果看你的文章没找到app文件,请问你是用app包裹了所有的Route吗?能否讲一下呢
        dkvirus:是的,app.js 是我项目里的文件,可能和你项目不一样。你是使用过程遇到啥问题了吗。
      • 潘逸飞:写的真好,感觉可以直接提个readme的PR给dva-loading
        dkvirus:@潘逸飞 😂
      • 3840d2462cce:假如是有状态组件的话,怎么拿到loading
        3840d2462cce:@dkvirus 我的是项目,拿到loading了,但没有效果,我给加你qq吗?截图给你看下?
        3840d2462cce:@dkvirus 没有用,还是拿不到,index.js引入 dva-loading 插件了,也是通过connect传递的,报错loading is defined
        dkvirus:只要你用的是dva,在入口文件 index.js 中引用 dva-loading 插件,之后在 routes 文件中通过 connect() 函数就能拿到 loading 对象,loading 作为 connect 的参数传递的。上面第一点中都有对应代码。
      • 枫_6769:我的组件是class定义的,怎么写app的这部分代码呢,在哪个生命周期写呢试了试都没成功呢;
        那颗星_fcaf:写在 const mapStateToProps = ({ logList, loading }) => ({
        logList,
        isLoading: loading.effects['logList/fetchLogList'],
        });
        dkvirus:不清楚你说的 app 是指哪里的代码?
      • RageCoke:注册一个号表达一下感谢,之前找了一段时间关于 dva loading 的资料,没有什么资料。。 在这里发现了:pray:
        dkvirus:@RageCoke 是的,我以前找也没找到,就自己摸索出这用法,想着记下来给其他迷糊的兄弟用
      • c982b7a1c203:请问下我用dva-loading的时候,打印loading显示model下是空,没有我当前的model是什么原因,我是dva-loading 0.3.0
        dkvirus:@pikaqiuchu 你的页面显示是否正常,你的models里的数据是否有显示。数据加载成功就说明models加载是没问题的。如果还不行,代码是你自己写的demo,可以发我邮箱949582269@qq.com,我给你调试看下
        c982b7a1c203:@dkvirus 你好,我是用动态路由中的dynamic函数加载的model,请问下是哪里没设置么?
        dkvirus:@pikaqiuchu 不好意思,这两天比较忙现在才看到。dva api 中有一个 app.models() 用于注册 models,不知道你是否有注册你的 model,注册过的 model 在 Loading 对象中都会有值的。如:loading.models={app: false, user: false},就表示当前 dva 注册了 app model 和 user model。

      本文标题:dva-loading 实践用法

      本文链接:https://www.haomeiwen.com/subject/rmlkuxtx.html