Open soda-x opened 7 years ago
@pigcan 很期待第二篇关于Electron和dva结合的文章呐。
楼主您好,我是电子工业出版社博文视点的编辑,请问您有计划出版前端方面的图书吗
@broadviewcheemi 您好,感谢,不过资历尚浅,暂无计划。
@pigcan 感谢您的回复,如果将来有计划,欢迎随时联系我
刚学dva,effects里的方法是dispatch调用的吗,怎么判断dispatch调用reducer还是effects里的方法啊,谢谢
@zhangxiaoru
确切说 dispatch 用以触发 action,而 action 是一个对象,该对象中会用来描述 需要调用的 reducer 或者 effects,以及调用传递的数据。
怎么判断dispatch调用reducer还是effects里的方法啊
没明白你问的什么,触发一个 action 时的 type 你在写的时候不就已经知道是 reducer 还是 effects 么。
66666
你说的啥。。。。可以再加一个demo。。。。ok
请问那个图可以再详细一点吗?同时state不是只根据model中的reducer更改吗?
请教一下dva测试reducer和effetc怎么写呐,官网没有找到详细的说明,但是看你上面给出的目录里面有tests,而我的dva-cli初始化的项目却没有呢?
我想问下关于reducer的内容:
reducers:{ add(state, action){ return { ...state, name: action.payload } } }
和 下面这种写法有什么区别么?
reducers:{ add(state, action){ state.name = action.payload; return state } }
缩进不起作用。 主要就是 返回一个新的state 和 再原state上做修改,然后返回有什么区别? 我两个都试了试好像没什么区别,官方文档上是说返回一个新的state @pigcan
@PleaseTryAgain
主要是怕有引用问题吧
从我的理解的来说,reducer并不是我们去改变state的地方,reducer应该是纯函数,只负责计算state,不负责存储state,如果在reducer里面直接修改state就相当于去存储state了。
@PleaseTryAgain
主要是怕有引用问题吧
官方是这样说的: 这种特性简单理解就是每次操作都是返回一个全新的数据(独立,纯净),所以热重载和时间旅行这些功能才能够使用 但是我在时间旅行上看不出来有什么差别。。。。
近期,我们在内部做了一个类似 IDE 性质的应用,基于 electron 和 dva,由于之前一直只关注 node 相关的开发者工具,并未太多接触 React 等内容,所以这段时间过的有点煎熬同时也很兴奋,煎熬来源于非舒适区,而兴奋来源于发现基于 dva + electron 给开发者工具带来了更多的可能性。
此次开发 IDE 项目组织方式已由 sorrycc 同学整理成脚手架 dva-boilerplate-electron。
初识 dva 是此次总结的第一篇文章,第二篇文章我会记录下在 electron 中的相关沉淀。
回归正题,如何在几天内玩好 React、Dva、Electron。
React 基础知识
什么是 React o.o ?
React 的核心目的是创建 UI 组件,也就是说它是 MVC 架构中的 V 层,所以 React 和你的技术架构并没有关系。
打个比方来说在 AngularJS 1.x 中它通过扩展 html 标签,注入一些结构性的东西(比如 Controllers, Services),所以 AngularJS 1.x 是会侵入到你整个技术的架构,从某些方面来说这些抽象确实能解决一些业务问题,但由此而来的是塔缺乏了灵活性。
React 这种仅仅关注在 Components 的库,给了开发者非常强的灵活度,因为我不并不会被束缚在某一个技术架构。
Components 在各个生命周期内发生了什么 ?
the-component-lifecycle
总结来讲
从最上层来说 React Component 生命周期可以落入到以下三个环节:
在这三个类别下分别对应着一些 React 的抽象方法,这些方法都是在组件特定生命周期中的钩子,这些钩子会在组件整个生命周期中执行一次或者多次。明白了这些钩子的调用时机,可以有助于更好的书写组件。
比如:
componentWillMount
: 在组件render
之前执行且永远只执行一次。componentDidMount
: 组件加载完毕之后立即执行,并且此时才在 DOM 树中生成了对应的节点,因此我们通过 this.getDOMNode() 来获取到对应的节点。等等详细请看 文档。
component 的几种创建方式
如果想了解更多的基础
Flux 又是什么鬼
简而言之 Flux 是一种架构思想,和 MVC 一样,用以解决软件结构的问题,如上所说 React 只是涉及了 UI 层所以在搭建大型应用时必须要有与之配套的应用架构。在 React 社区大家普遍使用 Flux 架构的思想来搭建应用,目前 flux 前端框架。
Flux 中最为显著的特点就是它的单向数据流,核心目的是为了在多组件交互时能避免数据的污染。
在 flux 模式中 Store 层是所有数据的权利中心,任何数据的变更都需要发生在 store 中,Store 层发生的数据变更随后都会通过事件的方式广播给订阅该事件的 View,随后 View 会根据接受到的新的数据状态来更新自己。任何想要变更 Store 层数据都需要调用 Action,而这些 Action 则由 Dispatcher 集中调度,在使用 Actions 时需要确保每个 action 对应一个数据更新,并同一时刻只触发一个 action。
说一说我个人的感受,在以往 MVC 架构中,某一个 Model 的数据可能被多个 View 共享,而每个 View 在通常情况下都会有自己的 Controller 层来代理 Model 和 View,那样子很显著的一个问题就出现了,任何一个 Controller 都可能会引发 Model 的数据更新,在现实中我们的应用通常拥有更为复杂的 UI 层,所以使用稍有不当我们的数据流将乱如麻,在调试中我们也会越来越难以调试,因为我们很难确定数据变更发生的确切位置。
dva 中的数据流
如何来理解呢?
在 web 应用中,数据的改变通常发生在用户交互行为或者浏览器行为(如路由跳转等),当此类行为改变数据的时候可以通过
dispatch
发起一个 action,如果是同步行为会直接通过Reducers
改变State
,如果是异步行为会先触发Effects
然后流向Reducers
最终改变State
,所以在 dva 中,数据流向非常清晰简明,并且思路基本跟开源社区保持一致。dva 的基本概念
什么是 dva
dva 的基本概念有哪些?
以下内容基本摘自 Dva Concepts
dva - Model
State
State 表示 Model 的状态数据,通常表现为一个 javascript 对象(immutable data)。
Action
Action 是一个普通 javascript 对象,它是改变 State 的唯一途径。无论是从 UI 事件、网络回调,还是 WebSocket 等数据源所获得的数据,最终都会通过 dispatch 函数调用一个 action,从而改变对应的数据。 需要注意的是
dispatch
是在组件 connect Models以后,通过 props 传入的。以上调用函数内的对象就是一个 action。
dispatch 函数
用于触发 action 的函数,action 是改变 State 的唯一途径,但是它只描述了一个行为,而 dipatch 可以看作是触发这个行为的方式,而 Reducer 则是描述如何改变数据的。
dva - Reducer
在 dva 中,reducers 聚合积累的结果是当前 model 的 state 对象。通过 actions 中传入的值,与当前 reducers 中的值进行运算获得新的值(也就是新的 state)。需要注意的是 Reducer 必须是纯函数。
dva - Effect
Effect 被称为副作用,在我们的应用中,最常见的就是异步操作,
Effects
的最终流向是通过Reducers
改变State
。核心需要关注下 put, call, select。
dva - Subscription
Subscriptions 是一种从 源 获取数据的方法,它来自于 elm。
Subscription 语义是订阅,用于订阅一个数据源,然后根据条件 dispatch 需要的 action。数据源可以是当前的时间、服务器的 websocket 连接、keyboard 输入、geolocation 变化、history 路由变化等等。
dva - Router
这里的路由通常指的是前端路由,由于我们的应用现在通常是单页应用,所以需要前端代码来控制路由逻辑,通过浏览器提供的 History API 可以监听浏览器url的变化,从而控制路由相关操作。
dva 实例提供了 router 方法来控制路由,使用的是react-router。
详见 react-router
dva - Route Components
在 dva 中我们通常以页面维度来设计 Container Components。
所以在 dva 中,通常需要 connect Model的组件都是 Route Components,组织在
/routes/
目录下,而/components/
目录下则是纯组件(Presentational Components)。通过 connect 绑定数据
比如:
然后在 App 里就有了
dispatch
和users
两个属性。好了,如上就是 dva 中的一些核心概念,起初看的时候可能一下子接收到的信息量颇大,但是不要着急,后续业务中的使用会让你对于如上概念越来越清晰。
那么如何来启动一个 dva 应用呢
Done o.o
让我们来一窥 dva 项目
src
目录结构,尝试来明白整体的代码的组织方式assets
: 我们可以把项目 assets 资源丢在这边components
: 纯组件,在 dva 应用中 components 目录中应该是一些logicless
的 component, logic 部分均由对应的 route-component 来承载。在安装完 dva-cli 工具后,我们可以通过 dva g component componentName 的方式来创建一个 component。index.css
: 首页样式index.html
: 首页index.js
: dva 应用启动五部曲
,这点稍后再展开models
: 该目录结构用以存放 model,在通常情况下,一个 model 对应着一个 route-component,而 route-component 则对应着多个 component,当然这取决于你如何拆分,个人偏向于尽可能细粒度的拆分。在安装完 dva-cli 工具后,我们可以通过dva g model modelName
的方式来创建一个 model。该 model 会在index.js
中自动注册。router.js
: 页面相关的路由配置,相应的 route-component 的引入routes
: route-component 存在的地方,在安装完 dva-cli 工具后,我们可以通过dva g route route-name
的方式去创建一个 route-component,该路由配置会被自动更新到route.js
中。route-component 是一个重逻辑区,一般业务逻辑全部都在此处理,通过connect
方法,实现 model 与 component 的联动。services
: 全局服务,如发送异步请求tests
: 测试相关utils
: 全局类公共函数dva 的五部曲
好了,以上便是五部曲,看了 dva 官方文档的可能说还少一步
原因是在实际业务中,我们的 connect 行为通常在 route-component 中进行设置。
以上。
对了,人为新增 model 后记得 model 要在 index.js 中予以注册,当然使用脚手架功能并不存在这个问题。 XD。