Open sorrycc opened 8 years ago
updeep 也说了,对于大数据量效率没有 immutable.js 高效,不如推荐 immutable.js
saga这个词是cqrs来的,是用来监听多个事件,同步事件的,比如创建订单会锁定库存,创建订单对象,当锁定库存和创建订单对象都成功时会处理的方法,所有的action都放里面感觉不是很合适
虽然没用过react,但看看前边说围绕着几个概念在转比较赞同,开发思维感觉又清晰了点
Nice introduction!
赞,急需
saga 的用途在这个例子里面没有讲清楚。
function createRequest () {
return (dispatch, getState) => {
dispatch({ type: 'REQUEST_STUFF' });
someApiCall(function(response) {
// some processing
dispatch({ type: 'RECEIVE_STUFF' });
});
};
}
这段代码和下面 saga 的代码区别只是 dispatch 变成了 put。someApiCall 变成了 generator 。
saga 的作用最主要还是解决复杂的异步交互情况,特别是竞争状态。参见 http://stackoverflow.com/questions/34930735/pros-cons-of-using-redux-saga-with-es6-generators-vs-redux-thunk-with-es7-async/34933395 saga 作者自己的回答。不过感觉对我们目前的业务来说 overkill 了。
saga 是通用方案,不管是简单还是复杂,有些业务看起来简单,但说不定有一个点的异步逻辑比较复杂呢。竞争状态是其中的一个场景,我觉得他最重要的点是可以统一管理业务代码,并且只需要接收一个 action 来触发。
:+1:
看着 saga 就觉得好熟悉。
上面例子,saga 在前端用,使用 generator 似乎区别只是异步改为同步写法而已。
generator 最大的问题,如果是高级浏览器还好,要兼容低版本的浏览器,需要一堆转换代码,感觉不是很好。在我们的业务中,异步请求是很小的一部分操作,如果后台是自己控制,页面中的数据,基本上一次请求就都拿过来了。同样,可以在前端操作页面,最终完成后,进行一次提交,完成所有的修改。这种情况下,异步操作,用最简单的 thunk 就够了。
看成了 Soga 😄
赞,正在学习~
赞!
saga, 一开始还以为是日文, 这前台的概念真是越来越多了...
👍,正在学习
好文!
前人栽树后人乘凉,很棒,公司内部项目准备就这么玩
@sorrycc 可以可以,先看看内部实现,这样用dva相对思路更清晰些,直接用框架,有点黑盒的感觉。喜欢看源码=。=
dva中saga的takeLatest可以在哪里设置?
多个应用整合的场景不知道大家有没有考虑过,有没有一些好的实践方式?
比如,后台管理类系统,非常庞大,是由N多个业务领域相对独立的管理系统组成的。 虽然应用开发与部署相对独立,但是我们肯定希望对于用户来讲,能提供较为统一的体验:将各个系统整合起来,提供统一的导航、菜单、页面布局等等。
以往传统的开发形式,可能有 iframe、后端渲染 import 等等方法。 但在 React 这种 SPA 的应用中,不知道有啥好的处理方式。尤其是公共的部分,是可能会包含业务逻辑,不是纯粹的“展示组件”。 即使,在不考虑与老系统的兼容情况下,只是多个React 的 SPA 整合,路由的处理之类的也还没想到很顺畅的方法。
我说的这种场景,有点类似于阿里云的管理控制台(从使用上来看,觉得相似)。阿里的管理控制台应该是 angularjs 实现。其细节不太清楚。
@clarkhan 我们是把公共部分提取成 npm 包。
@sorrycc 包含业务逻辑么。比如单应用中可能用 action -> reducer 处理的部分,甚至是 ajax 等会封装到 有“业务状态和处理逻辑”的组件中?
@clarkhan 这个问题可以参考Elm的架构,如果每个公共组件都分别提供reducer/action/view/model,使用者将这些碎片自由组合的话就没什么问题,elm中ajax是在Reducer中触发的,所以ajax也可以复用。这种程度的复用即使是redux-saga也做不到(因为依赖顶层的middleware)
但是,个人认为这种针对副作用的复用是非常非常极端的情况,比如ajax,即使组件拆成了对全局无依赖的碎片,ajax本身通常也会依赖到全局的token
@clarkhan 我们是基于 dva 来做的,公共的部分包含 component 和 model,ajax(effect) 和 reducer 都封到一起。
@kpaxqin 可以看下 dva,和 elm 参考了很多概念过来。
@sorrycc 一直在关注。等着 1.0 release 会在部分项目尝试使用。不过其中的 saga 我们之前没有在用,可能会是迁移的一个障碍?
总之很期待。加油!
@sorrycc 我的意思是,即使是elm也很难较好地处理这类情况 elm分形的基础是组件没有对全局的依赖。而事实上涉及到副作用,对全局的依赖(比如token)是不可避免的。
全局依赖基于约定? 比如 token 就约定从 cookie 里获取。
@sorrycc 工程上可以这么做,有异步行为的通常是针对一定业务领域的复用了,使用范围有限定的话加这些约定没啥问题。
但从架构的角度这种约定其实还是比较弱的,这也是我对elm架构的一个concern,所谓的完全分形在实际场景下是受限制的。
还有个concern是leaf节点问题,同样的问题cycle.js也有,虽然他们宣称是分形架构,但最终的叶子节点(比如一个div)还是基于属性 + 事件
、不可分形的。
这种差异会带来分形的边界问题,比如cycle的作者最近就支持Web Component,因为基于某个架构创建组件的成本更高、通用性更低(只能适配一个架构),而基于WC的组件大家都可以用。理论上答案可以概括为"无业务的通用组件做成WC,有业务的按项目架构来",实际工程中这个边界的把握就完全看团队水平了。
不过上面这个concern是针对elm/cycle类强制分形流的,react/redux本来就不用管这个
好文,学习
redux-saga 的替代方案:redux-observable。
原因:
劣势:
关于 redux-saga
可以看出,调整之后的代码有几个优点: 所有业务代码都存于 saga 中,不再散落在各处 全同步执行,就算逻辑再复杂,看起来也不会乱
看下 redux thunk 的新版介绍
Any return value from the inner function will be available as the return value of dispatch itself. This is convenient for orchestrating an asynchronous control flow with thunk action creators dispatching each other and returning Promises to wait for each other’s completion:
就是说一个 action creator 返回一个 async function 的话, dispatch 这个 async function 的返回值是一个 Promise, 又可以 await 了
拿 redux-saga readme 例子来说 https://redux-saga.github.io/redux-saga/index.html
export function USER_FETCH_REQUESTED(){
return async (dispatch, getState) => {
try{
const user = await Api.fetchUser(action.payload.userId)
} catch(e) {
dispatch({type: "USER_FETCH_FAILED", message: e.message})
return
}
dispatch({type: "USER_FETCH_SUCCEEDED", user: user})
}
}
// 然后在 View里
diapatch(USER_FETCH_REQUESTED())
redux-thunk + promise 这个业务也都在 action creator 中, 而且显式的 dispatch 一个 thunk, 比 redux-saga 使用 takeEvery/takeLatest 将一个操作与 action type 关联的做法要好, 俨然一个黑箱. 如果是引用的话编辑器或IDE可以直接点击跳过去
redux-saga takeEvery / takeLatest / 数据相关的可能比较好用...但文中这两点不那么有力... 对于公司项目, 我还是倾向简单一些, 有时候入口 action creator 都不写了, 直接写在 event handler 里
btw Vuex 的 action 也是可以使用 async/await. 方便多了
赞
云谦师兄我现在也在阿里的技术栈中 在使用dva 但是现在遇到很多不懂得问题 想请教你
您好,我在使用dva roadhog,现在每次build都是index.css index.js 请问怎么能自动加上版本号 比如 index323232.css index232323.js 谢谢。
@albafica2015 还不支持,请关注这个 issue,https://github.com/sorrycc/roadhog/issues/69
好的,非常感谢,我去roadhog文件包里面找到了webpack.prod.js,里面把js css加上了[hash],但是生成的html没有自动换路径。发自网易邮箱大师
在2017年03月08日 08:17,chencheng (云谦) 写道: @albafica2015 还不支持,请关注这个 issue,sorrycc/roadhog#69
—You are receiving this because you were mentioned.Reply to this email directly, view it on GitHub, or mute the thread.
{"api_version":"1.0","publisher":{"api_key":"05dde50f1d1a384dd78767c55493e4bb","name":"GitHub"},"entity":{"external_key":"github/sorrycc/blog","title":"sorrycc/blog","subtitle":"GitHub repository","main_image_url":"https://cloud.githubusercontent.com/assets/143418/17495839/a5054eac-5d88-11e6-95fc-7290892c7bb5.png","avatar_image_url":"https://cloud.githubusercontent.com/assets/143418/15842166/7c72db34-2c0b-11e6-9aed-b52498112777.png","action":{"name":"Open in GitHub","url":"https://github.com/sorrycc/blog"}},"updates":{"snippets":[{"icon":"PERSON","message":"@sorrycc in #1: @albafica2015 还不支持,请关注这个 issue,https://github.com/sorrycc/roadhog/issues/69"}],"action":{"name":"View Issue","url":"https://github.com/sorrycc/blog/issues/1#issuecomment-284904380"}}}
@albafica2015 html 需要通过 htmlwebpackplugin 生成,现在是直接 copy 的。
云谦师兄 dva的思想不好懂啊
我想问一下,如果我的项目有一千多个页面,那么我该以什么粒度去区分modal?我觉得modal以route页面来区分,可能开发过程modal会拆分的比较好,但是在redux的store下面会存一千多个平级的state;而如果以一类相似对route页面来区分,大概有两百多个modal,感觉这样的话每一个modal会略复杂,多个route共用一个modal。
@sunOpar 我觉得平级state不是问题,本身你这些页面之间没什么关系的话,最好是分开。如果要做一定程度的复用,可以从业务实体的角度出发,但最好还是跟state隔离开
请问考虑过mobxjs吗
搞c++的路过,原来我不会看代码。。。。
@xiemeilong 我用 MobX 实现了一套 https://github.com/djyde/cans
大神,借宝地一用。 想请教一下:在项目中使用了redux,知道智能组件和展示组件的区别。可不可以在智能组件中使用react原始的this.state来控制自身内容展示和隐藏。即操作this.setState()的方法。
@clarkhan 随着业务越来越多,也遇到了同样的问题。感觉还是得在原有的基础上再拆一层。
@sunOpar @xufei
我觉得按route拆model(modal一般指模态窗吧?)是对的,elm的状态树本身就是随着组件树组合的,根结点自然就是route。redux里需要预定义state tree才引申出了怎么拆的问题。
按这个思路平级state是【不必要】存在的,每个页面都单独初始化store就行了,单独拥有自己的root reducer,这也更接近redux的模仿对象——elm的做法
至于复用,创建reducer所需要的函数本来就是可复用的,创建的过程也可以进行抽象,所以页面间逻辑复用不会有问题。
跨页面之间数据共享的需求,不应该走redux store,而应该由localstorage/api等手段来解决,因为store是存在内存中的,一刷新就没了。严格区分页面的external resource我认为是更好的实践
请问dva 与mobx 区别有什么?
前端变化虽快,但其实一直都围绕这几个概念在转:
在 redux 的生态圈内,每个环节有多种方案,比如 Data 可以是
immutable
或者plain object
,在你选了immutable
之后,用 immutable.js 还是 seamless-immutable,以及是否用 redux-immutable 来辅助数据修改,都需要选择。本文总结目前 react + redux 的最佳实践,解释原因,并提供可选方案。
心急的朋友可以直接看代码:https://github.com/sorrycc/github-stars
一、URL > Data
需求
routing
选择
react-router + react-router-redux: 前者是业界标准,后者可以同步 route 信息到 state,这样你可以在 view 根据 route 信息调整展现,以及通过 action 来修改 route 。
可选
无
二、Data
需求
为 redux 提供数据源,修改容易。
方案
plain object
: 配合 combineReducer 已经可以满足需求。同时在组织 Store 的时候,层次不要太深,尽量保持在 2 - 3 层。如果层次深,可以考虑用 updeep 来辅助修改数据。
可选
immutable.js: 通过自定义的 api 来操作数据,需要额外的学习成本。不熟悉 immutable.js 的可以先尝试用 seamless-immutable,JavaScript 原生接口,无学习门槛。
另外,不推荐用 redux-immutable 以及 redux-immutablejs,一是没啥必要,具体看他们的实现就知道了,都比较简单;更重要的是他们都改写了
combineReducer
,会带来潜在的一些兼容问题。三、Data > View
需求
数据的过滤和筛选。
方案
reselect: store 的 select 方案,用于提取数据的筛选逻辑,让 Component 保持简单。选 reselct 看重的是
可组合特性
和缓存机制
。可选
无
四、View 之 CSS 方案
需求
合理的 CSS 方案,考虑团队协作。
方案
css-modules: 配合 webpack 的 css-loader 进行打包,会为所有的 class name 和 animation name 加 local scope,避免潜在冲突。
直接看代码:
Header.jsx
Header.less
编译后,文件中的
style.normal
和.normal
在会被重命名为类似Header__normal___VI1de
。可选
bem, rscss ,这两个都是基于约定的方案。但基于约定会带来额外的学习成本和不遍,比如 rscss 要求所有的 Component 都是两个词的连接,比如
Header
就必须换成类似HeaderBox
这样。radium,inline css 方案,没研究。
五、Action <> Store,业务逻辑处理
需求
统一处理业务逻辑,尤其是异步的处理。
方案
redux-saga: 用于管理 action,处理异步逻辑。可测试、可 mock、声明式的指令。
可选
redux-loop: 适用于相对简单点的场景,可以组合异步和同步的 action 。但他有个问题是改写了
combineReducer
,会导致一些意想不到的兼容问题,比如我在特定场景下用不了 redux-devtool 。redux-thunk, redux-promise 等: 相对原始的异步方案,适用于更简单的场景。在 action 需要组合、取消等操作时,会不好处理。
saga 入门
在 saga 之前,你可能会在 action creator 里处理业务逻辑,虽然能跑通,但是难以测试。比如:
然后组件里可能这样:
这样通过 redux state 和 reducer 把所有的事情串联到起来。
但问题是:
通过 saga,你只需要触发一个 action 。
然后所有后续的操作都通过 saga 来管理。
可以看出,调整之后的代码有几个优点:
六、Data <> API Server
需求
异步请求。
方案
isomorphic-fetch: 便于在同构应用中使用,另外同时要写 node 和 web 的同学可以用一个库,学一套 api 。
然后通过
async
+await
组织代码。示例代码:
可选
reqwest
最终
(完)