dva 2.0 发布
sorrycc opened this issue · 79 comments
距离 dva@1 发布已经快整整一年,经过一段时间断断续续的开发,dva@2 终于能和大家见面了。
2.0 最主要的变化是提取了 dva-core,是仅封装了 redux 和 redux-saga 的纯数据流方案。这使得 dva 可以应用在除 react 之外的其他领域,比如 RN、小程序、游戏、vue 等领域;同时也可满足同一领域的多种实现,比如为 react 应用不同的路由方案的 dva-react-router-3 和 dva-no-router。(#530)
本次发布包含 dva-core 和 3 个 react 实现:
- dva@2.0:基于 react 和 react-router@4
- dva-react-router-3@1.0:基于 react 和 react-router@3
- dva-no-router@1.0:无路由版本,适用于多页面场景,可以和 next.js 组合使用
- dva-core@1.0:仅封装了 redux 和 redux-saga
此外,还有一些社区基于 dva-core 的实现:
- dva-wxapp,dva 应用于微信小程序
改进
dispatch(effectAction) => Proimse
为了方便在视图层 dispatch action 并处理回调,比如 #175,我们在 dispatch 里针对 effect 类型的 action 做了返回 Promise 的特殊处理。
例如:
dispatch({ type: 'count/addAsync' })
.then(() => {
console.log('done');
});
新增 dva/dynamic 接口,配合 react-router@4 处理组件的按需加载
react-router@4 的路由是组件式的,手动处理组件的按需加载并结合 model 和 app 有点麻烦,所有封装了 dva/dynamic
util 方法。
const Users = dynamic({
app,
models: () => [
import('./models/users'),
],
component: () => import('./routes/Users'),
});
// render
<Route exact path="/users" component={Users} />
take 自动补全 namespace 前缀
注:之前手动加 namespace 的会收到一个 warning。
{
namespace: 'count',
effects: {
*a(action, { take }) {
// Before
yield take('count/b');
// After
yield take('b');
}
}
}
effect 前后会额外触发 /@@start
和 /@@end
的 action,可利用此约定实现 put 的同步执行
例如:
yield put({ type: 'addDelay', payload: { amount: 2 } });
yield take('addDelay/@@end');
const count = yield select(state => state.count);
yield put({ type: 'addDelay', payload: { amount: count, delay: 0 } });
参考用例 dva/effects-test.js at d49e3567eaadf06d12c701e670b2ba3bbe043553 · dvajs/dva · GitHub 。
Break Changes
react-router@4
路由基于 react-router@4 实现,写法上会有不同。
同名 reducer 和 effect 不会 fallthrough(即两者都执行),而是仅执行 effect
// model.js
export default {
namespace: 'count',
reducers: {
a() {},
},
effects: {
*a() {},
}
}
// 只会执行 effects.a 不会执行 reducers.a
dispatch({ type: 'count/a' });
删除 dva/mobile
之前的 dva/mobile
其实是无路由版的 dva,所以可以用 dva-no-router 代替。
history 的 location 属性上不再包含 query
这是 history 库的变动,有和 query 相关的请用 query-string 处理一遍。
FAQ
dva@1.0 用户如何升级?
原则上推荐升级到基于 react-router@4 的 dva@2,react-router@4 路由的去中心化带来的好处绝对值得一学,比如布局嵌套、Inclusive 路由、路由抽象等等。可以参考 user-dashboard 升级到 dva@2 的 commit 。
但肯定会有出于成本考虑,既想用 dva@2,又想继续用老版本的路由方案的,我们为大家准备了 dva-react-router-3。大家可以参考 dva-example-react-router-3 进行升级。而为了减少代码修改量,比如把所有的 import xx from 'dva'
改成 import xx from 'dva-react-router-3'
,大家可以通过 babel-plugin-module-resolver 进行构建时替换:
["module-resolver", {
"alias": {
"dva": "dva-react-router-3"
}
}]
(完)
前排占楼,跟不上前端时代潮流了
点赞
同名 reducer 和 effect 不会 fallthrough(即两者都执行),而是仅执行 effect
为什么有这个修改呢?
准备跟进..
@kenan2002 因为加了 dispatch(effectAction) => Promise
的功能,action 到 effect 这一层就返回了,到不了 reducer 。
重学react-router@4 是个大项目...
前排
mark,晚上学习跟进
dispatch(effectAction) => Proimse
👍👍👍
看到小程序可以用dva-core,我就放心了
准备升级看看
同名 reducer 和 effect 不会 fallthrough(即两者都执行),而是仅执行 effect
感觉这个改动有点大,修改了原生 redux 的行为,容易采坑
赞,准备开始学dva,紧跟前端潮流,哈哈哈
dva-boilerplate-electron 是否会更新dva@2.0?
同名 reducer 和 effect 不会 fallthrough(即两者都执行),而是仅执行 effect
感觉这个改动太大了,之前很多代码基于此的,很方便的在effect执行之前先修改state
dispatch(effectAction) => Proimse
这个改动好像使得dva的使用方式可以多元化了,比如可以 把数据放在react的state里面了,dispatch effect -> promise -> update state. 而不是像以前必须要通过reducer了,这个改动好或者坏?
有没有dva 2.0完成的demo
d.ts
有吗?
写得太精彩了。6666666。由衷佩服那个添加一个promiseMiddlerware,并把对应的reslove和reject生成一个map,用于给saga调用的方案。居然还有这操作。。。。。
养肥了再用 嘿嘿
用dva-cli@0.8.1 dva new
新建的项目是基于dva@2.0 ,如果想用dva-react-router-3@1.0如何设置?
升级到2.0之后 全局的onError不起作用了?
一直没有结合 immutable 的方案呢
onError这个钩子没作用了
@Gavinchen92
Route
现在是组件了,钩子函数的操作可以在容器组件的生命周期里去做
参考
各个子项目的文档有了吗,我翻了一下 README.md 都是空的
养肥了把 你们先把坑填好
dispatch(effectAction) => Proimse
这个太实用了
dva 可以接小程序,点赞!!
怎么将 hashHistory 改成 browserHistory 啊?
请问,怎么根据用户是否登录来进行路由的跳转啊???
牛
dva2.0 没有atool-build的demo吗,急需
@sorrycc 最后FAQ一段里,user-dashboard 升级到 dva@2 的 commit
这句的链接指向的是旧的版本,代码已经不对了,希望可以改一下,避免其他人再按照错误示例迁移。
我是用pathname==“/”监听初始页面,在mapStateToProps获取初始数据出现异步
const { issues, numbers: numberor } = state.bet;
console.log(issues);此处在state.bet未获取完成数据之前执行,怎么回事
你好,打扰你一下,请问一下我如果想将项目中的图片放在cdn上去,在roadhogrc里面怎么配置?配置publicPath的话全部都会变成cdn路径 @sorrycc
用的前一个版本做的项目,如果不升级的话会不会有影响?
@sorrycc 用的前一个版本做的项目,如果不升级的话会不会有影响?
ant-design-pro 切换为browserHistory 刷以后白屏
@sorrycc 请问一下,我照着
@daskyrk 请问一下,dva@1升级到dva@2怎么配置啊,上面的教程不行,配置了之后报错,求帮忙解决啊
Dispatch =>promise 实在好,明天准备试一试
Reactjs 中的 Dva 这么一封装,有点vuejs的感觉了,Models 对应 vue 组件的Script,整合了页面响应和Store;模板是独立组件,对应vuejs的Templet。Dvajs的好处是用vue的方式来使用React,可以使用React的丰富的生态资源。vuejs更容易上手和理解,所有概念都整合在一起,不用管细节就能用,弱项是生态
我用dva-cli 创建项目后 不安装不了其他库了,是什么原因
有点MST的意思,但定位为framework就限制了很多可能并提高了使用门槛。
请问一下,这个生成的项目的模板是index.ejs,可以改成index.html吗,我在index.ejs里引用的css都不生效不知道怎么回事。
蹲坑观摩,还在使用@dva1.X
needs english translation please :)
同名 reducer 和 effect 不会 fallthrough(即两者都执行),而是仅执行 effect
@sorrycc 在 PromiseMiddleware 判断 isEffect 的逻辑里 增加一个 判断是否是 reducers 的方法 isReducer ,如果是 reducers 则 同时调用一下 next(action) 确保 reducer 也可以对该 action 进行处理。不知这么处理是否可行 ?
同名 reducer 和 effect 不会 fallthrough(即两者都执行),而是仅执行 effect
这个改动感觉是设计被实现牵着鼻子走了。这个breaking change的解释竟然是因为另一处升级而导致的副作用?实在是匪夷所思。且不论原因,这个设计上的变化也是不合理的。
所谓effects,可以理解为side effects,其为action的伴随效果,或副作用,表现为对action(reducer)进行纯扩展(不改动原有逻辑,而增加扩展逻辑,支线逻辑,旁路逻辑,或曰,副逻辑),这自然而然。而这个breaking change改变了这个设定,让effects实际上变成了async action,实在不妥,不仅破坏了api的兼容性,而且逻辑和命名也反而变得矛盾了。
其实async action并非不好,但这次升级完全可以通过增加async action的方式来实现,而非改变一个定义准确的概念还破坏了兼容性。我觉得这个breaking change是dva2设计上的灾难。
@zhaoyao91 派发 action,同时触发同名 reducer 和 effect 的使用场景是什么?
例如做一个log或者发一个数据统计。或者,状态是改成requesting-data,而side effect是实际执行拉取动作,完成后更新状态为data-fetched或failed。
用例是一方面,关键是一个功能的效果应该是和其概念定义保持。如果觉得没有这个用例,那大可不要这个feature,而做一个async action的feature,而不是因为图方便而混淆概念。
请问一下,dva2.X的onerror钩子没有了?
需要好好学习下dva了 , 光是用redux确实写的相同的东西太多.
dva-react-router-3 无法通过编译,好像是需要调用react-router-3但是实际使用了react-router-4,怎么回事呢。。
时隔几个月,才发现新版本发布了。
请问.umirc.mock怎么用。。。。
好实用.赶紧试用一下.
@sorrycc 现在有一个问题请教下
dva@2.0+后是需要react@16.0+ 但是dva-cli 后 react-router-redux@5.0.0-alpha.6 确要react@15.0
是不是可以忽略它
@sorrycc 你好,能否把 dva-example-react-router-3 再发一下,现在已经打不来,打算升级dva而不升级路由
app.model(require('./models/users').default);有default和没有default有什么区别?default是后来加的吗?因为我现在做的项目中没有default也能运行,而根据文档写的demo却会报错.
大家好~
// 1. Initialize
const app = dva({
onReducer: (reducer) => {
if (createPersistorIfNecessary(app._store)) {
const newReducer = persistReducer(persistConfig, reducer)
setTimeout(() => $persistor && $persistor.persist(), 0)
return newReducer
} else {
return reducer
}
},
history: createHistory(),
onError,
})
createPersistorIfNecessary(app._store)的app_store 是 null, 而且一直出现“redux-persist failed to create sync storage, falling back to memory storage", 恳切大家可以回复协助,谢谢
dispatch(effectAction) => Proimse 为了方便在视图层 dispatch action 并处理回调,比如 #175,我们在 dispatch 里针对 effect 类型的 action 做了返回 Promise 的特殊处理。
这个把reducers中的方法封装一下放到effect里,这样间接的reducers也可以进行Promise回调的操作。
@kenan2002 因为加了
dispatch(effectAction) => Promise
的功能,action 到 effect 这一层就返回了,到不了 reducer 。
那如果在这个effect里发出了另一个触发reducer的action,这种情况呢, 会到reducer吗
同名 reducer 和 effect 不会 fallthrough(即两者都执行),而是仅执行 effect
感觉这个改动太大了,之前很多代码基于此的,很方便的在effect执行之前先修改state
dispatch(effectAction) => Proimse
这个改动好像使得dva的使用方式可以多元化了,比如可以 把数据放在react的state里面了,dispatch effect -> promise -> update state. 而不是像以前必须要通过reducer了,这个改动好或者坏?
确实扩展了action的使用。现在可以把dispatch action的使用分为两个场景:
- 当需要在视图内使用dispatch action并根据回调改变视图的state时, 使用 dispatch(effectAction) - promise - update component state。 此时不允许有同名的reducer, 因为action到effect这一层就返回了。
- 经典的使用场景: dispath(action) - reducer - effect - state。
那么> > dispatch(effectAction) => Proimse只是提供了快捷,并没有改变之前使用场景的数据流
可以这么理解吗?
同名 reducer 和 effect 不会 fallthrough(即两者都执行),而是仅执行 effect
看了下源代码,在 PR dvajs/dva#1602 之后这个行为已经改变了,现在能够正常地 fall through。
这个修改包含在 2.2.0 开始的版本中。
@nelhu @zhaoyao91
@sorrycc 如果设计目的上并没有特意禁止同名 reducer 和 effect 的话,这个 bug 算是 fix 了;建议更新一下文章。
我升dva2后,路由切换会触发double次监听,且都是PUSH的,搞得很无奈。
yield put({ type: 'addDelay', payload: { amount: 2 } });
yield take('addDelay/@@EnD');
const count = yield select(state => state.count);
yield put({ type: 'addDelay', payload: { amount: count, delay: 0 } });
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
可不可以这样写呢
yield (yield put({ type: 'addDelay', payload: { amount: 2 } });)
const count = yield select(state => state.count);
yield put({ type: 'addDelay', payload: { amount: count, delay: 0 } });
yield put({ type: 'addDelay', payload: { amount: 2 } });
yield take('addDelay/@@EnD');
const count = yield select(state => state.count);
yield put({ type: 'addDelay', payload: { amount: count, delay: 0 } });
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
可不可以这样写呢
yield (yield put({ type: 'addDelay', payload: { amount: 2 } });)
const count = yield select(state => state.count);
yield put({ type: 'addDelay', payload: { amount: count, delay: 0 } });
可以的
而且可以省略括号