sorrycc/blog

12 步 30 分钟,完成用户管理的 CURD 应用 (react+dva+antd)

sorrycc opened this issue · 357 comments

本文仅适用于 dva@1,dva@2 的文档请移步 #62
本文仅适用于 dva@1,dva@2 的文档请移步 #62
本文仅适用于 dva@1,dva@2 的文档请移步 #62

本文会一步步引导大家如何创建一个 CURD 应用,包含查询、编辑、删除、创建,以及分页处理,数据 mock,自动处理 loading 状态等,基于 react, dvaantd

最终效果:

开始之前:

  • 确保 node 版本是 6.5 +
  • cnpmyarn 能节约你安装依赖的时间

Step 1. 安装 dva-cli 并创建应用

先安装 dva-cli,并确保版本是 0.7.x。

$ npm i dva-cli@0.7 -g
$ dva -v
0.7.0

然后创建应用:

$ dva new user-dashboard
$ cd user-dashboard 

Step 2. 配置 antdbabel-plugin-import

babel-plugin-import 用于按需引入 antd 的 JavaScript 和 CSS,这样打包出来的文件不至于太大。

$ npm i antd --save
$ npm i babel-plugin-import --save-dev

修改 .roadhogrc,在 "extraBabelPlugins" 里加上:

["import", { "libraryName": "antd", "style": "css" }]

Step 3. 配置代理,能通过 RESTFul 的方式访问 http://localhost:8000/api/users

修改 .roadhogrc,加上 "proxy" 配置:

"proxy": {
  "/api": {
    "target": "http://jsonplaceholder.typicode.com/",
    "changeOrigin": true,
    "pathRewrite": { "^/api" : "" }
  }
},

然后启动应用:(这个命令一直开着,后面不需要重启)

$ npm start

浏览器会自动开启,并打开 http://localhost:8000

访问 http://localhost:8000/api/users ,就能访问到 http://jsonplaceholder.typicode.com/users 的数据。(由于 typicode.com 服务的稳定性,偶尔可能会失败。不过没关系,正好便于我们之后对于出错的处理)

Step 4. 生成 users 路由

用 dva-cli 生成路由:

$ dva g route users

然后访问 http://localhost:8000/#/users

Step 5. 构造 users model 和 service

用 dva-cli 生成 Model :

$ dva g model users

修改 src/models/users.js

import * as usersService from '../services/users';

export default {
  namespace: 'users',
  state: {
    list: [],
    total: null,
  },
  reducers: {
    save(state, { payload: { data: list, total } }) {
      return { ...state, list, total };
    },
  },
  effects: {
    *fetch({ payload: { page } }, { call, put }) {
      const { data, headers } = yield call(usersService.fetch, { page });
      yield put({ type: 'save', payload: { data, total: headers['x-total-count'] } });
    },
  },
  subscriptions: {
    setup({ dispatch, history }) {
      return history.listen(({ pathname, query }) => {
        if (pathname === '/users') {
          dispatch({ type: 'fetch', payload: query });
        }
      });
    },
  },
};

新增 src/services/users.js

import request from '../utils/request';

export function fetch({ page = 1 }) {
  return request(`/api/users?_page=${page}&_limit=5`);
}

由于我们需要从 response headers 中获取 total users 数量,所以需要改造下 src/utils/request.js

import fetch from 'dva/fetch';

function checkStatus(response) {
  if (response.status >= 200 && response.status < 300) {
    return response;
  }

  const error = new Error(response.statusText);
  error.response = response;
  throw error;
}

/**
 * Requests a URL, returning a promise.
 *
 * @param  {string} url       The URL we want to request
 * @param  {object} [options] The options we want to pass to "fetch"
 * @return {object}           An object containing either "data" or "err"
 */
export default async function request(url, options) {
  const response = await fetch(url, options);

  checkStatus(response);

  const data = await response.json();

  const ret = {
    data,
    headers: {},
  };

  if (response.headers.get('x-total-count')) {
    ret.headers['x-total-count'] = response.headers.get('x-total-count');
  }

  return ret;
}

切换到浏览器(会自动刷新),应该没任何变化,因为数据虽然好了,但并没有视图与之关联。但是打开 Redux 开发者工具,应该可以看到 users/fetchusers/save 的 action 以及相关的 state 。

Step 6. 添加界面,让用户列表展现出来

用 dva-cli 生成 component:

$ dva g component Users/Users

然后修改生成出来的 src/components/Users/Users.jssrc/components/Users/Users.css,并在 src/routes/Users.js 中引用他。具体参考这个 Commit

需留意两件事:

  1. 对 model 进行了微调,加入了 page 表示当前页
  2. 由于 components 和 services 中都用到了 pageSize,所以提取到 src/constants.js

改完后,切换到浏览器,应该能看到带分页的用户列表。

Step 7. 添加 layout

添加 layout 布局,使得我们可以在首页和用户列表页之间来回切换。

  1. 添加布局,src/components/MainLayout/MainLayout.js 和 CSS 文件
  2. src/routes 文件夹下的文件中引用这个布局

参考这个 Commit

注意:

  1. 页头的菜单会随着页面切换变化,高亮显示当前页所在的菜单项

Step 8. 通过 dva-loading 处理 loading 状态

dva 有一个管理 effects 执行的 hook,并基于此封装了 dva-loading 插件。通过这个插件,我们可以不必一遍遍地写 showLoading 和 hideLoading,当发起请求时,插件会自动设置数据里的 loading 状态为 true 或 false 。然后我们在渲染 components 时绑定并根据这个数据进行渲染。

先安装 dva-loading :

$ npm i dva-loading --save

修改 src/index.js 加载插件,在合适的地方加入下面两句:

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

然后在 src/components/Users/Users.js 里绑定 loading 数据:

+ loading: state.loading.models.users,

具体参考这个 Commit

切换到浏览器,你的用户列表有 loading 了没?

Step 9. 处理分页

只改一个文件 src/components/Users/Users.js 就好。

处理分页有两个思路:

  1. 发 action,请求新的分页数据,保存到 model,然后自动更新页面
  2. 切换路由 (由于之前监听了路由变化,所以后续的事情会自动处理)

我们用的是思路 2 的方式,好处是用户可以直接访问到 page 2 或其他页面。

参考这个 Commit

Step 10. 处理用户删除

经过前面的 9 步,应用的整体脉络已经清晰,相信大家已经对整体流程也有了一定了解。

后面的功能调整基本都可以按照以下三步进行:

  1. service
  2. model
  3. component

我们现在开始增加用户删除功能。

  1. service, 修改 src/services/users.js
export function remove(id) {
  return request(`/api/users/${id}`, {
    method: 'DELETE',
  });
}
  1. model, 修改 src/models/users.js
*remove({ payload: id }, { call, put, select }) {
  yield call(usersService.remove, id);
  const page = yield select(state => state.users.page);
  yield put({ type: 'fetch', payload: { page } });
},
  1. component, 修改 src/components/Users/Users.js,替换 deleteHandler 内容:
dispatch({
  type: 'users/remove',
  payload: id,
});

切换到浏览器,删除功能应该已经生效。

Step 11. 处理用户编辑

处理用户编辑和前面的一样,遵循三步走:

  1. service
  2. model
  3. component

先是 service,修改 src/services/users.js

export function patch(id, values) {
  return request(`/api/users/${id}`, {
    method: 'PATCH',
    body: JSON.stringify(values),
  });
}

再是 model,修改 src/models/users.js

*patch({ payload: { id, values } }, { call, put, select }) {
  yield call(usersService.patch, id, values);
  const page = yield select(state => state.users.page);
  yield put({ type: 'fetch', payload: { page } });
},

最后是 component,详见 Commit

需要注意的一点是,我们在这里如何处理 Modal 的 visible 状态,有几种选择:

  1. 存 dva 的 model state 里
  2. 存 component state 里

另外,怎么存也是个问题,可以:

  1. 只有一个 visible,然后根据用户点选的 user 填不同的表单数据
  2. 几个 user 几个 visible

此教程选的方案是 2-2,即存 component state,并且 visible 按 user 存。另外为了使用的简便,封装了一个 UserModal 的组件。

完成后,切换到浏览器,应该就能对用户进行编辑了。

Step 12. 处理用户创建

相比用户编辑,用户创建更简单些,因为可以共用 UserModal 组件。和 Step 11 比较类似,就不累述了,详见 Commit


到这里,我们已经完成了一个完整的 CURD 应用。但仅仅是完成,并不完善,比如:

  • 如何处理错误,比如请求等
  • 如何处理请求超时
  • 如何根据路由动态加载 JS 和 CSS
  • ...

请期待下一篇。

(完)

简直好用到哭,😂

Ygg-w commented

这就是我想要的东西~👍👍👍

Ygg-w commented

期待下一篇~

dispatch(routerRedux.push({
pathname: '/users',
query: { page },
}));

routerRedux 可以直接切换路由?
如果是这样的话 也太方便的吧 之前是从最终的组件一直disptach行为

routerRedux.push() 返回的是 action,然后把他让 dispatch 调用下就可以切换路由了。

uwang commented

👍 最近文档更新的越来越易读了

期待新作,,,

现在的项目在用是 dva 0.60,,可以直接升级到0.70吗

@linyongping dva-cli@0.6 ? 到 0.7 主要是工具的变动,要换到 roadhog,可以参考 #17

image
请问要支持await还需要配置什么吗

@gitoneman await 必须在 async 函数里。

@sorrycc 谢谢,对await不熟悉

请问npm start出现这个错误

`npm start

@ start /Users/feiya200/Documents/user-dashboard
roadhog server

/Users/feiya200/Documents/user-dashboard/node_modules/roadhog/bin/roadhog.js:9
const [major, minor] = nodeVersion.split('.');
^

SyntaxError: Unexpected token [
at exports.runInThisContext (vm.js:53:16)
at Module._compile (module.js:373:25)
at Object.Module._extensions..js (module.js:416:10)
at Module.load (module.js:343:32)
at Function.Module._load (module.js:300:12)
at Function.Module.runMain (module.js:441:10)
at startup (node.js:139:18)
at node.js:990:3

npm ERR! Darwin 15.6.0
npm ERR! argv "/usr/local/Cellar/node@4/4.7.0/bin/node" "/usr/local/bin/npm" "start"
npm ERR! node v4.7.0
npm ERR! npm v2.15.9
npm ERR! code ELIFECYCLE
npm ERR! @ start: roadhog server
npm ERR! Exit status 1
npm ERR!
npm ERR! Failed at the @ start script 'roadhog server'.
npm ERR! This is most likely a problem with the package,
npm ERR! not with npm itself.
npm ERR! Tell the author that this fails on your system:
npm ERR! roadhog server
npm ERR! You can get information on how to open an issue for this project with:
npm ERR! npm bugs
npm ERR! Or if that isn't available, you can get their info via:
npm ERR!
npm ERR! npm owner ls
npm ERR! There is likely additional logging output above.

npm ERR! Please include the following file with any support request:
npm ERR! /Users/feiya200/Documents/user-dashboard/npm-debug.log
`

node 版本要求 6.5 或以上。

oops

请问,我想配置端口怎么设置?因为本地想开多个 dva 项目,但是改不了端口。
npm start 改成这个了:

"start": "dora --plugins \"proxy?port=8089&watchDirs=./mock,webpack,webpack-hmr\""

但是还有个 8000 端口

...
          proxy: listened on 8089
Caught exception: Error: listen EADDRINUSE :::8000
...

@sorrycc

@llqgit 参考 #17 切换到 roadhog,然后 PORT=8001 npm start 就好了。

@sorrycc 好,谢谢

报错,npm start之后~~~
Failed to compile.
Error in ./src/index.js
Module build failed: Error: Plugin 3 specified in "base" provided an invalid property of "libraryName"
at Array.map (native)
@ multi index

TFous commented

想问下,为什么打包之后页面不能正常访问了。

@TFous 如果是用的 browserHistory,打包后需要放根目录路由才会匹配到。

payload的传参不知道到怎么在model里面获取到的。

@leduold reducer 的第二个参数,或者 effect 的第一个参数就是 action,详见 API 文档

关于components和routes在这次的demo中有一个疑惑,之前的demo中主张components只是展示型组件,不处理逻辑,routes是容器组件,state绑定到props和dispatch(action)都放在routes组件中,这次却看到放在了components/Users.js里,这样做与之前比是有什么好处吗?个人觉得放在routes比较好,统一便于管理。

@FEliuyg 放在 routes 里只能一层层传下去,层级多了很麻烦,修改、新增都麻烦。

@sorrycc 层级多了确实挺麻烦的,要修改很多地方。那哪种是比较推崇的写法呢?之前看文档说展示型组件只关心外观,容器型组件处理工作,那这样做虽然少了麻烦,与之前约定的会不会有相违背呢?

@FEliuyg 看个人喜好吧,我是实用主义者。。不能接受太麻烦的事情。

问下统一处理错误请求、请求超时有详细文档么!(守望先锋~~)

@cytellme

统一错误处理可以用 onError hook,

const app = dva({
  onError(e) {
    console.log(e.message);
  }
});

然后用返回 Promise 的请求库(比如 dva/fetch),或者把请求封装成 Promise。并在出错,超时等时机 reject 这个 Promise。reject 的信息会自动走到 onError 里。

已解决!非常感谢回答 @sorrycc

问一下,在创建和编辑user的时候,现在的做法是都去创建一个model与之前创建和编辑共用并只创建一个model相比有没有什么优势,第二个疑问是,原来的mock数据现在采用了jsonplaceholder,如果业务复杂数据需要较多的时候,如何mock多字段多条数据,这种情况是不是还是原来的mockjs会更好用些?

请教一下,dva怎么卸载css module?用了css module之后,className会自动加后缀,导致页面不正确。

@FEliuyg

在创建和编辑user的时候,现在的做法是都去创建一个model与之前创建和编辑共用并只创建一个model相比有没有什么优势。

优势是实现起来更简单,不用去维护 model 的 visible 状态以及切换 form 数据。

原来的mock数据现在采用了jsonplaceholder,如果业务复杂数据需要较多的时候,如何mock多字段多条数据,这种情况是不是还是原来的mockjs会更好用些?

下周会在 roadhog 上实现 mock 方案,在 sorrycc/roadhog#22 更新进度。

@xhmaoxx

请教一下,dva怎么卸载css module?用了css module之后,className会自动加后缀,导致页面不正确。

https://github.com/sorrycc/roadhog#disablecssmodules

mark

之前那个例子如果先搜索出结果,点击下一页,搜索内容就不起作用了,就会重新加载所有列表内容,期望可以修复下。

我想问一下这个api/users的数据是怎么产生,怎么找不到api的文件夹却有数据呢?里面是用到什么插件虚拟数据吗? @sorrycc

@dicklwm 仔细看第三步,配了代理的。

@sorrycc 你没出现报错的情况吗?

2017-01-11 20:08 node[1915] (FSEvents.framework) FSEventStreamStart: register_with_server: ERROR: f2d_register_rpc() => (null) (-21)
2017-01-11 20:08 node[1915] (FSEvents.framework) FSEventStreamStart: register_with_server: ERROR: f2d_register_rpc() => (null) (-21)
2017-01-11 20:08 node[1915] (FSEvents.framework) FSEventStreamStart: register_with_server: ERROR: f2d_register_rpc() => (null) (-21)
2017-01-11 20:08 node[1915] (FSEvents.framework) FSEventStreamStart: register_with_server: ERROR: f2d_register_rpc() => (null) (-21)

好多条这样的,查了一下。。原因可能是因为npm的问题。。

它会导致代码修改后,不会热更新,然后服务得要重启才得看到最新代码的效果。。

但我当前的:

  • node (6.9.4)
  • npm(3.10.10)

所以我想知道一下您那里的node版本是多少,npm版本是多少?

@henryzp 没遇到过这个问题。我的 node 是 6.5,npm 是内部的 npm 版本,不过你可以选择用 cnpm

Failed to compile.

Error in ./src/services/users.js
Module not found: /api/users in /Users/encorehe/mycode/web/ylbAdmin/src/services

@ ./src/services/users.js 49:9-53

请问一下 一直报这个错 是因为什么啊?

services/users.js 里引用了 /api/users ?

查询条件的表单 怎么写

build以后,proxy配置的接口地址不管用了。 还有,生产环境怎么样起服务比较好?

Ygg-w commented

@sorrycc 想要roadhog支持ts,需要怎么做?

Failed to compile.

Error in multi index
Module not found: 'babel' in E:\user-dashboard

@ multi index

按照步骤来,怎么报这个错 cnpm i --save-dev babel 后也不行


后面使用 npminstall 就好了 (或者使用npm) 使用cnpm好像会有点问题

TFous commented

自己做了一个写了一个例子,现在是加载图片,然后动态的设置图片的宽度,现在问题是无法获取到实际的dom元素,请问有什么好的方法么?

dva new app 的时候怎么默认使用NPM呢?

Ygg-w commented

@TFous 用ref来做

nimoc commented

@TFous

function getImageSize(url, callback) {
    var img = new Image()
    img.src = url
    img.onload = function () {
        callback({
            width: img.width,
            height: img.height
        })
    }
}
getImageSize('https://avatars1.githubusercontent.com/u/3949015?v=3&s=460', function (size) {
    console.log(size) // {width: 400, height: 400}
})
getImageSize('https://avatars2.githubusercontent.com/u/35128?v=3&s=88', function (size) {
    console.log(size) // {width: 88, height: 88}
})
TFous commented

@nimojs
谢啦,自己解决了。和你这个差不多;

handleImg(dom, w, h) {
        const Img = dom;
        Img.onload = function () {
            function setImgSize(dom, w, h) {
                if (Img.offsetWidth > w) {
                    Img.width = w;
                    if (Img.offsetHeight > h) {
                        w -= 5;
                        setImgSize(dom, w, h);
                    }
                }
            }
            setImgSize(dom, w, h)
        }
    }

    componentDidMount() {
        Object.keys(this.refs).forEach(key => this.handleImg(this.refs[key], 220, 140))
    }

    componentDidUpdate() {
        Object.keys(this.refs).forEach(key => this.handleImg(this.refs[key], 220, 140))
    }

谢谢分享!

文中有个地方需要校正一下:

"Step 11. 处理用户编辑" 章节中:

"我们在这里如何处理 Model 的 visible 状态"

里的 Model 应该是 Modal

太棒了。期待下一篇大作

ali的人就是不错,有问必答,👍

报错呀,
还有这个回复格式不知道怎么弄,排版不好呀

{
"entry": "src/index.js",
"disableCSSModules": true,
"autoprefixer": null,
"proxy": {
"/typicode": {
"target": "http://jsonplaceholder.typicode.com/",
"changeOrigin": true,
"pathRewrite": { "^/typicode" : "" }
}
},
"extraBabelPlugins": [
"transform-runtime",
["import", { "libraryName": "antd", "style": true }]
],
"env": {
"development": {
"extraBabelPlugins": [
"dva-hmr",
"transform-runtime"
]
},
"production": {
"extraBabelPlugins": [
"transform-runtime"
]
}
}
}
`

{

"entry": "src/index.js",
"disableCSSModules": true,
"autoprefixer": null,
"proxy": {
"/typicode": {
"target": "http://jsonplaceholder.typicode.com/",
"changeOrigin": true,
"pathRewrite": { "^/typicode" : "" }
}
},
"env": {
"development": {
"extraBabelPlugins": [
"dva-hmr",
"transform-runtime",
["import", { "libraryName": "antd", "style": "css" }]
]
},
"production": {
"extraBabelPlugins": [
"transform-runtime",
["import", { "libraryName": "antd", "style": "css" }]
]
}
}
}
`

两种都报错:

1

执行 这一句的时候:

用 dva-cli 生成路由:

$ dva g route users

@sorrycc 你好 一步一步写 遇到个问题:
`
browser.js:40Uncaught Error: plugin.use: plugin should be plain object
at invariant (browser.js:40)
at Plugin.use (plugin.js:52)
at dva (createDva.js:114)
at Object. (Users.js:66)
at webpack_require (bootstrap dd89df2…:555)
at fn (bootstrap dd89df2…:86)
at Object. (Users.js:4)
at webpack_require (bootstrap dd89df2…:555)
at fn (bootstrap dd89df2…:86)
at Object. (router.js:5)

`

解决了。
原因:
import {connect} from 'dva'; // 之前没有加大括号
import styles from './Users.css'; // 给styles加了大括号

请问怎么在effects里面触发组件里面的方法啊?譬如添加用户请求后台成功后,要给出一个modal成功提示。

ldc4 commented

遇到一个谜之bug:
根据上面教程一步一步的做,做到编辑这部分的时候,点击编辑按钮,页面就刷新了。
经过调试,发现会莫名其妙的执行到unloadTriggered函数,就是在这里页面就刷新了。
然后,我clone完整示例下来,对比代码。发现并没有什么不同。
唯一不同的是:

  showModelHandler = (e) => {
    if (e) e.stopPropagation();
    this.setState({
      visible: true,
    });
  };

关于这段代码中的stopPropagation高亮颜色不一样。。。
我的是紫色(表示属性)的,官方的是金色(表示方法)的。
然而代码一模一样。

之后,我把官方的代码拷贝覆盖了一下就正常了。。

各位大神,你们怎么看这个现象。运行的时候并没有报错,表现为点击编辑,然后页面刷新了。在调试状态可以看到modal框弹出来。

@NTmemoir 试试添加一个“modal成功提示”的state再model里面,effects里面调用put刷新对应的state,在对应的component里面为对应的state设置显示方式,应该可以

@ldc4 覆盖官方的代码后,diff看看那些地方不一样,可能看漏了吧,我自己看着做了一遍,但是你这段“if (e) e.stopPropagation();” 我没有写,也执行通过了,你也可以去掉试一下,还有看一下onClick里面设置了showModelHandler没有

请问怎么在effects里面触发组件里面的方法啊?

@NTmemoir https://github.com/dvajs/dva-knowledgemap#put

期待第二篇文章啊

你好,我在执行到第三步时,即使还没有修改.roadhogrc文件,在访问/api/anypath时,浏览器都报这个错误:Uncaught SyntaxError: Unexpected token < index.js:1 ,后面修改.roadhogrc文件配置后依然如此,配置没有问题,npm start可以正常启动。
我试了三次都是同样的结果,不知哪里出了问题。
环境:chrome dva 0.7.8 node 7.2.1

即使还没有修改.roadhogrc文件,在访问/api/anypath时,浏览器都报这个错误:Uncaught SyntaxError: Unexpected token < index.js:1

/api/anypath 没有处理过,会默认输出 index.html 的内容,而由于路径的问题,/api/anypath 会访问不到 index.js,所以报这个错误是符合预期的。

要让 /api/anypath 有输出,要通过 roadhog 的 mock 功能进行 mock。

@Marchdongming 光看日志看不出来是啥问题。

按照教程来,执行 dva g route users 时,报错:
Error: Cannot find module 'babel-runtime/helpers/slicedToArray'
at Function.Module._resolveFilename (module.js:470:15)
at Function.Module._load (module.js:418:25)
at Module.require (module.js:498:17)
at require (internal/module.js:20:19)
at Object. (/usr/local/lib/node_modules/dva-cli/lib/generate.js:7:23)
at Module._compile (module.js:571:32)
at Object.Module._extensions..js (module.js:580:10)
at Module.load (module.js:488:32)
at tryModuleLoad (module.js:447:12)
at Function.Module._load (module.js:439:3)

node: 7.4
npm 4.0.5

@lee-my node 换 6.x 试试,最近收到好几个反馈了,都是 node 7 的。

@sorrycc 试了下 用0.7.0版本 dva g 命令没问题,0.7.9(现在最新版)有问题

npm run build后的项目文件,放到本地服务器下,请求的接口地址为:
image

请问是否可以请求到proxy里面配置的地址?
image

TFous commented

models 里的effects是基于saga实现的吧

redux开发者工具怎么用的啊

Users是一个Functional Component,里面却定义了许多函数,这样每次重新渲染时,就要重新定义这些函数,对性能有影响吧?

修改 .roadhogrc,在 "extraBabelPlugins" 里加上:

["import", { "libraryName": "antd", "style": "css" }]

上面的描述的操作,如何操作:
extrababelplugins

发现其它地方有示例了:
https://ant.design/docs/react/practical-projects-cn#下一步
extrababelplugins-docs

image

“Failed to compile.

Error in ./src/utils/request.js
Module build failed: TypeError: D:/EX/NODEJS/user-dashboard/src/utils/request.js: Property declaration of ExportDefaultDeclaration expected node to be of a type ["FunctionDeclaration","ClassDeclaration","Expression"] but instead got "VariableDeclaration"
@ ./src/services/users.js 8:15-42”

@sorrycc 大神,你好!
我直接clone 您的项目https://github.com/dvajs/dva-example-user-dashboard.git,npm start运行报上面的这个错误。
我按照教程,在第5步以后,运行也出现同样的错误。
npm -v 3.10.8
node -v v6.9.1
dva -a 0.78

@bladethirst 出错提示很明显了,export default 输出了变量声明,而不是 ["FunctionDeclaration","ClassDeclaration","Expression"]

@sorrycc
大神,感谢答复。
但上面的报错是我直接clone你的项目,没有修改一处,运行报的错。
我刚刚学react+redux不久,正准备学习dva,请见谅。


webpack 的版本有关吗?
我的webpack是2.2.1。

我同事取下dva-example-user-dashboard后,他的webpack是1.14.0版本,可以正常运行。我用npm install webpack@1.14.x --save-dev后,还是报同样的错。我就不知道问题出在哪了,是哪句export default错了?

是因为/services/users.js里面
export default async function request(url, options)
的async关键字的原因吗?
babel没识别出它是关键字?

@sorrycc
找到原因了,问题出在export default async function request(url, options)中的async上,
参考babel/babel#3786
最终改写为
async function request(url, options)
…………
export { request as default }
就可以了。

Failed to compile.

Error in ./src/index.js
Module not found: ./index.html in D:\dva\user-dashboard\src

@ ./src/index.js 11:0-23

Failed to parse mock config.

Error in Maximum call stack size exceeded (While processing preset
RangeError: "D:\dva\user-dashboard\node_modules\roadhog\node_modules\babel
-preset-es2015\lib\index.js")

前面可以看到页面,但数据请求不到,到处理loading状态时报出这个错误,请指教

为什么yield put(someAction)会阻塞,但yield put(someEffect)不会阻塞呢

ldc4 commented

@Stephenzd 我也遇到这个问题了,比如获取用户信息,我单独写在一个effect里面,然后再另一个effect中yield put不行

@ldc4 解决yield put(someEffect)不阻塞的问题了,我用了redux-saga的take。我的需求是把用户的token存在store里,每个effect里都用select获取store里的token,判断token是否过期,如果过期就调用refreshToken这个effect,问服务器要到新的token后,再调用reducer里的save,把原来store里的那个token更新,然后再select新的token。可是yield put(refreshToken)不阻塞,导致还没refresh就select了,结果当然select不到新的token。
我的办法是在yield put(refreshToken)后加一句yield take('user/save'),程序执行到take这里就会阻塞,直到执行了user/save,才会继续执行后面的select,所以可以select到新的token。

请求多个接口数据,比较数据,怎么做会比较好

ldc4 commented

@Stephenzd 虽然能行,但是我还是放弃这样做了。
获取用户信息,还是应该放在路由来做这个事情

把项目下载之后,npm run build 能打包成功,但是打开dist/index.html为什么页面不显示,也不报错,引入文件css,js都有,就是页面不显示,有遇到相似问题的亲吗

@sorrycc 你好,请教一下为什么编辑之后,重新拉取列表数据,再打开modal框,之前的编辑数据仍然保留,没有跟列表的当前实际记录对应呢?是不是由于案例中修改接口重新拉取的list数据没有变化,导致没有重新渲染???包括创建用户的时候,创建完自动拉取列表,之前的创建数据仍然保留,两种情况又有不同的是,编辑的时候,刷新完列表,点另一页再回来之前的编辑数据就没了,但创建时,就算点另一页再回来之前的编辑数据还是保留在上面,期待大神回复下小菜鸟😄

死在第一步:dva new myApp 中。创建文件不成功,报错信息:
dva-v 0.7.8
qq 20170309123132

@brucelc 因为代理

有没有视频啊 菜鸟哭瞎!!!!

@miaozilong 看视频都是学不到东西的。

@afc163
npm run build后生成了dist目录
目录下有以下文件
│ 1.1.js
│ 2.2.js
│ index.css
│ index.html
│ index.js

└─static
yay.44dd3333.jpg

请问下 这些文件拷贝到tomcat或者apache里怎么运行呀?

@sorrycc

  1. 后端代码在局域网服务器10.18.11.2
  2. 在本机系统hosts文件添加 10.18.11.2 xxx.app
  3. 浏览器直接请求http://xxx.app/roles 可以获取到数据
  4. 在前端代码里(基本和教程一样)按照教程配置代理,请求数据,报跨域问题。
    在网上查阅了一些资料,可以在后端加Access-Control-Allow-Origin或者像教程一样配置代理,试了下还是没解决问题。
    请问大神这样思路对吗,该如何解决。谢谢~

@shengKevin 可以,但是不建议这么用

@sorrycc 打包后代理就挂了,可以直接在index.js里面配置代理地址么

@lanxxg 跨域请求就是在后端加Access-Control-Allow-Origin,亲测可以

@sorrycc 速度更新第二弹了,“错误处理 如何处理请求超时”,期待大作

大家的删除和编辑都成功了吗?我操作了,但是列表的数据没有发生变化,求解。

已照着教程做完,灰常强大,楼上删除和编辑不成功是因为后台服务没有设定吧

@AtticusLv 后台怎么设定,求指导,本人服务端开发,前端不怎么熟