-
Notifications
You must be signed in to change notification settings - Fork 324
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
dva 入门:手把手教你写应用 #8
Comments
如果定义了多个model,model之间如何通信? |
@jerexyz 通过 action。dva 封装自 redux,通信机制也等同于 redux 。 |
问个题外话
这个怎么做到的? |
@sorrycc 源码没看到用到这个依赖 |
我 fork 了一份的,因为要优先用内部的 tnpm 作为安装工具。 |
希望文档中能够补充一下。 |
@ibigbug 都是很好的问题,说下我的理解。 问:onClick 的 dispatch 放在 Component 里面,keyUp 的 dispatch 写在 model 里面: 事件订阅放在两个地方? keyUp 可以当做是事件,也可以当做是数据源。作为事件,放 Component 比较合适;作为数据源,放 model 的 subscription 则更合适。 Subscription 语义是订阅,用于订阅一个数据源,然后根据条件 dispatch 需要的 action。keyUp 的事件绑定可以把他理解成是订阅了键盘事件的数据源。 而如果把 keyUp 放在 React Component,按我理解,应该是要放在 componentWillMount 之类的生命周期里。我不喜欢这么做,因为:
问:namespace 已经声明了,还要在每个方法见面加前缀么? 这是一个非常纠结的点。 我也希望把前缀去掉,但其实并不止需要去 key 里的前缀,reducers, effects 和 subscriptions 里 dispatch/put/take 的时候也要处理。 考虑一下原因,最终决定不去前缀:
问:如果想在页面加载时 load 一组数据该怎么写? 在 subscriptions 里写,因为 component 已经是 stateless 了。可以参考:https://github.com/dvajs/dva/blob/master/examples/user-dashboard/src/models/users.js#L20-L31 问:effect 里面参数如何传递? 通过 action 传递数据,effects 里可以去到 action 对象。 比如: const effects = {
*['a'](action) {
console.log(action.payload); // 1
},
};
dispatch({type: 'a', payload: 1}); 问:将 elm-lang 的 subscription,effect 的概念直接引入,是否有什么特殊考虑? 如果和大家已经熟知的 redux 概念差异较大,是否会增加理解和学习成本? subscription、effect 和 redux 的 reducer 并不冲突,他们解决的是不同的问题。至于为何要引入,主要是认同 elm 的概念,前端的好多库(包括 redux)都是从 elm 里借的概念;另外,用 redux 我们通常不会仅用 redux 本身,还需要各种插件的配合,而 subscription + effect + reducer 则很好的解决了我目前能想到的所有项目问题。 dva 在设计上会尽量保证 redux 用户的低迁移/使用成本,对 redux 用户友好。比如 api 设计上没有做过度封装。 |
为啥 阿里都喜欢用 less 嘞 |
@janjon 抱歉,api 变更了,这里换成 |
有几个疑问,希望可以帮忙解答下
|
effect 只能归属一个 model,修改其他 model 要 dispatch 该 model 的 action
用 model 内部变量,比如: const isEnable = true;
export default {
namespace: 'keyboard',
subscriptions: {
setup({ dispatch }) {
key('ctrl+up', () => {
if (isEnable) { /* do something with dispatch */ }
});
},
},
effects: {
*enable() {
isEnable = true;
},
*disable() {
isEnable = false;
},
}
}; |
@sorrycc 感谢~ |
webpack打包工具怎么加载字体文件就报错。该怎么配置。可以出个教程讲讲你这个webpack跟我们的不一样 |
blog开头贴的地址404 |
@Plortinus 感谢提醒,已更新。 |
如果存在页面上存在一个列表,列表里面每一项都对应于一个相同的model(每一项对应之前定义好的一个组件实例,类似于TodoList里面的每一个Todo,但是这个Todo也是进行了封装了,并且使用了Todo model,不是Plain Object),此时,这样的情况如何处理? |
dva new myApp |
访问 http://localhost:8000 呢? On Wed, Nov 9, 2016 at 9:29 AM, shenxiuqiang notifications@github.com
|
@sorrycc 请问,如果我想给.normal添加一个背景图片,直接在样式表里写background:url('xxx.png');报错,请问怎么解决? |
@spiroo 报什么错? https://github.com/dvajs/dva/issues 这里提 issue 吧。 |
最终打包想按需加载模块,不全在一个脚本里,应如何处理才好 |
按步骤写好了index.less,再index.js里也有写好import和className相关语句,但网页上没有出现样式。用浏览器开发工具查看页面代码,已看到css已出现,但在div里却没出现,求赐教 |
同上,完成后,css无效~ |
@yelgogogo .roadhogrc 里的配置要把CSSModules打开... |
请问写mock时用post方法如何获取到body传过来的参数
|
貌似并不会自动安装 keymaster 啊。。 |
如何实现嵌套的路由,像/products/edit/1234或者/products/view/1234, { path: '/',
component: App,
getIndexRoute(nextState, cb) {
require.ensure([], (require) => {
cb(null, {component: require('./routes/Home/')});
}, 'home');
},
childRoutes: [
{
path: 'products',
getComponent(nextState, cb) {
require.ensure([], (require) => {
cb(null, require('./routes/Product/index'));
}, 'products');
},
childRoutes: [
{
path: 'edit',
getComponent(nextState, cb){
require.ensure([], (require) => {
cb(null, require('./routes/Product/edit'));
}, 'productEdit');
},
},
],
},
],
} |
我import key from 'keymaster'后,并没有自动安装啊,运行报错说Module not found: 'keymaster' in ... |
监听页面加载完成之后 立刻执行 函数?或者在render之后执行函数,如何做呢? |
reducers 和 effects 同名的action 方法,effects的动作会覆盖 reducers 的动作吗?我的本地测试显示只执行了 effects 里面的 add 方法 |
@joshle 会,先执行reducers里面的方法,然后执行effects,俩个不能同名 |
其中 “完成 component” 小节中 dispatch 方法是如何传递的 |
请问,为什么component dispatch type 'count/add' 的actioner, 只执行了effects的add,而reducers的add确没有被执行呢? |
@Lifedance dva2.0还是某个版本后就不会同时触发effects和reducers了 |
作为后端码农,我竟然仔细了阅读了每一个issues,感谢并膜拜~ |
每次修改完代码后编译构建都很慢,请问如何做优化! |
model 什么时候会用到哇,感觉放在页面的state 里面好像就不需要model存放state了 |
我们将基于 dva 完成一个简单 app,并熟悉他的所有概念。
最终效果:
这是一个测试鼠标点击速度的 App,记录 1 秒内用户能最多点几次。顶部的 Highest Record 纪录最高速度;中间的是当前速度,给予即时反馈,让用户更有参与感;下方是供点击的按钮。
看到这个需求,我们可能会想:
在代码组织部分,可能会想:
以及:
我们可以带着这些问题来看这篇文章,但不必担心有多复杂,因为全部 JavaScript 代码只有 70 多行。
安装 dva-cli
那么,首先需要安装的是 dva-cli 。dva-cli 是 dva 的命令行工具,包含 init、new、generate 等功能,目前最重要的功能是可以快速生成项目以及你所需要的代码片段。
安装完成后,可以通过
dva -v
查看版本,以及dva -h
查看帮助信息。创建新应用
安装完 dva-cli 后,我们用他来创建一个新应用,取名
myApp
。注意:
--demo
用于创建简单的 demo 级项目,正常项目初始化不加要这个参数。然后进入项目目录,并启动。
$ cd myApp $ npm start
几秒之后,会看到这样的输出:
(如需关闭 server,请按 Ctrl-C.)
在浏览器里打开 http://localhost:8989/ ,正常情况下,你会看到一个 "Hello Dva" 页面。
定义 model
接到需求之后推荐的做法不是立刻编码,而是先以上帝模式做整体设计。
这个需求里,我们定义 model 如下:
namespace 是 model state 在全局 state 所用的 key,state 是默认数据。然后 state 里的 record 表示
highest record
,current
表示当前速度。完成 component
完成 Model 之后,我们来编写 Component 。推荐尽量通过 stateless functions 的方式组织 Component,在 dva 的架构里我们基本上不需要用到 state 。
注意:
import styles from './index.less';
,再通过styles.xxx
的方式声明 css classname 是基于 css-modules 的方式,后面的样式部分会用上count
和dispatch
,count
对应 model 上的 state,在后面 connect 的时候绑定,dispatch
用于分发 actiondispatch({type: 'count/add'})
表示分发了一个{type: 'count/add'}
的 action,至于什么是 action,详见:Actions@redux.js.org更新 state
更新 state 是通过 reducers 处理的,详见 Reducers@redux.js.org。
reducer 是唯一可以更新 state 的地方,这个唯一性让我们的 App 更具可预测性,所有的数据修改都有据可查。reducer 是 pure function,他接收参数 state 和 action,返回新的 state,通过语句表达即
(state, action) => newState
。这个需求里,我们需要定义两个 reducer,
count/add
和count/minus
,分别用于计数的增和减。值得注意的是count/add
时 record 的逻辑,他只在有更高的记录时才会被记录。注意:
{ ...state }
里的...
是对象扩展运算符,类似Object.extend
,详见:对象的扩展运算符add(state) {}
等同于add: function(state) {}
绑定数据
在定义了 Model 和 Component 之后,我们需要把他们连接起来。这样 Component 里就能使用 Model 里定义的数据,而 Model 中也能接收到 Component 里 dispatch 的 action 。
这个需求里只要用到
count
。这里的 connect 来自 react-redux。
定义路由
这个需求只有一个页面,路由的部分不需要修改。
注意:
history
默认是 hashHistory 并且带有_k
参数,可以换成 browserHistory,也可以通过配置去掉_k
参数。现在刷新浏览器,如果一切正常,应该能看到下面的效果:
添加样式
默认是通过 css modules 的方式来定义样式,这和普通的样式写法并没有太大区别,由于之前已经在 Component 里 hook 了 className,这里只需要在
index.less
里填入以下内容:效果如下:
异步处理
在此之前,我们所有的操作处理都是同步的,用户点击 + 按钮,数值加 1。
现在我们要开始处理异步任务,dva 通过对 model 增加 effects 属性来处理 side effect(异步任务),这是基于 redux-saga 实现的,语法为 generator。(但是,这里不需要我们理解 generator,知道用法就可以了)
在这个需求里,当用户点 + 按钮,数值加 1 之后,会额外触发一个 side effect,即延迟 1 秒之后数值 1 。
注意:
*add() {}
等同于add: function*(){}
takeEvery
),还可以选择takeLatest
,或者完全自定义take
规则刷新浏览器,正常的话,就应该已经实现了最开始需求图里的所有要求。
订阅键盘事件
在 dva 里有个叫 subscriontions 的概念,他来自于 elm。
Subscription 语义是订阅,用于订阅一个数据源,然后根据条件 dispatch 需要的 action。数据源可以是当前的时间、服务器的 websocket 连接、keyboard 输入、geolocation 变化、history 路由变化等等。
dva 中的 subscriptions 是和 model 绑定的。
这里我们不需要手动安装 keymaster 依赖,在我们敲入
import key from 'keymaster';
并保存的时候,dva-cli 会为我们安装keymaster
依赖并保存到package.json
中。输出如下:所有代码
index.js
构建应用
我们已在开发环境下进行了验证,现在需要部署给用户使用。敲入以下命令:
输出:
该命令成功执行后,编译产物就在 dist 目录下。
下一步
通过完成这个简单的例子,大家前面的问题是否都已经有了答案? 以及是否熟悉了 dva 包含的概念:model, router, reducers, effects, subscriptions ?
还有其他问题?可以关注 dva repo 了解更多细节。
(完)
The text was updated successfully, but these errors were encountered: