Coder Social home page Coder Social logo

dvajs / dva Goto Github PK

View Code? Open in Web Editor NEW
16.2K 437.0 3.2K 2.32 MB

🌱 React and redux based, lightweight and elm-style framework. (Inspired by elm and choo)

Home Page: https://dvajs.com/

License: MIT License

JavaScript 100.00%
dva redux redux-saga framework elm

dva's People

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

dva's Issues

initialState参数配置

initialState参数,必须要将namespace里面的所有state全部写出来
类似这样的结构

 {
 namespace: {
   ...state
  }
}

initialState能不能只写namespace中部分的state,因为state部分是在model中设置了初始化值的。
而动态创建dva的时候只希望部分initialSate有用。

在 effects 如何抛出一个错,让全局onError捕获?

在index.js里写

import { message } from 'antd';
// 1. Initialize
const app = dva({
    onError(error) {
        message.destroy();
        message.error(error);
  },
});

在models里

... 
effects: { //params action,effect
    * query({payload},{put, call, select}) {
        //如何抛出一个error?
    },
...

讨论:mobile 版接口

@nikogu @yiminghe @afc163 @ChrisFan

大家怎么选? 主要是 dva.router 拿来配 root component 是否合适。


方案 1:

import dva from 'dva/mobile';
const app = dva();
dva.model({});
dva.router(App);
dva.start('#root');

方案 2:

import dva from 'dva/mobile';
const app = dva();
dva.model({});
const Dva = dva.start();
ReactDOM.render(() => <Dva><App /></Dva>, document.getElementById('root'));

或者其他方案?

Failed prop type: Invalid prop `children` supplied to `Router`.

从0.0.16升级到了1.0.0-beta4,出现了这个问题。

import React, { PropTypes } from 'react';
import { Router, Route, IndexRedirect } from 'dva/router';
import IndexPage from './routes/IndexPage';
import Example from './routes/Example';
// import LoginPage from './routes/LoginPage';

export default ({ history }) => {
  return (
    <Router history={ history }>
      <Route breadcrumbName="首页" path="/" >
        <IndexRedirect to="example" />
        <Route component={ IndexPage } >
          <Route breadcrumbName="样例" path="example" component={ Example } />
        </Route>
      </Route>=
    </Router>
  );
};

如何在Route离开的时候清除某个model.namespace的state数据。

我在开发中,很多最下层的route,离开后它的一些state数据其实没有用了,我希望在对应的route离开的时候清除这些state的数据,减少内存中的数据。

我看subscription是适合写route leave的地方,现在官方的例子有history.listen,我要怎么写才是监听onLeave?再有就是我怎么清除store里面某个model.namespace的数据?在注销的时候,我怎么清除整个redux的state?

effects 命名有要求吗?

命名为
fuzzyQueryCourse
queryCollection
均无法调用,在后面加上数字就可以(eg:fuzzyQueryCourse1)...

还有,effects中可以调用当前model中的其他effects吗?
业务场景:
1.获取视频列表
2.修改查询条件,获取视频列表

我现在的做法,是先disptach 修改条件,再dispatch获取视频列表

Extend effects, support takeLatest and takeEvery

const effects = {
  // default: takeEvery
  ['setQuery']: function*() {},
  // takeLatest
  ['setQuery']: [function*() {}, { type: 'takeLatest'}],
  // you don't need to set type for takeEvery, it's by default.
  ['setQuery']: [function*() {}, { type: 'takeEvery'}],
}

现在这个架构下如何通过state验证来做路由跳转

现在这个架构下如何通过state验证来做路由跳转

我想实现的是state保存登陆状态,未登录跳转到/login路由下

  • router.js无法获取state,无法通过onEnter来实现;
  • IndexPage.jsx里做路由跳转必须使用有状态组建;

还是说在 api 请求的时候验证登录状态而不是通过state?

[讨论] API 设计

重新思考了下 api 的设计和功能,做了一些调整。欢迎讨论。

API

app = dva(opts?)

  • opts.onError: 默认 throw 出错信息,在 effectsubscription 出错时被调用。

app.model(obj)

Takes the following arguments:

  • namespace: model state 在全局 state 上所在的 key 值
  • state: model 的初始值
  • reducers: 同步操作,用于更新数据,由 action 触发
  • effects: 异步操作,不直接更新数据,由 action 触发,可以 dispatch action
  • subscriptions: 异步只读操作,不直接更新数据,可以 dispatch action

一个完整的例子:

app.model({
  namespace: 'count',
  state: 0,
  reducers: {
    ['count/add'  ](count) { return count + 1 },
    ['count/minus'](count) { return count - 1 },
  },
  effects: {
    ['count/add']: function*(action) {
      yield call(delay, 1000);
      yield put({
        type: 'count/minus',
      });
    },
  },
  subscriptions: [
    function(send) {
      key('⌘+up'  , () => { dispatch({type: 'count/add'}); });
      key('⌘+down', () => { dispatch({type: 'count/minus'}); });
    },
  ],
});

namespace 是 model 在全局 state 上所占的 key,格式为字符串。虽然叫 namespace,但像 a.b 并不会被扩展为 globalState.a.b

state 是 plain object 。

reducers 对应 redux 的 reducer,格式为 object/array。默认是 object,如果要支持 reducer enhancer,需要写成 array,第二个参数为 reducer enhancer 。例:

app.model({
  reducers: [{}, reducerEnhander],
});

effects 对应 redux-saga。他有类型,takeEverytakeLatest。默认是 takeEvery,如果想要 takeLatest,可以这样:

app.model({
  effects: {
    ['count/add']: [function*(){}, { type: 'takeLatest' }],
  },
});

上面 reducerseffects 的扩展配置的方式都是通过数组第二项的方式进行配置,参考自 babel

subscriptions 用于订阅数据源,格式为数组,他们会在 domready 时被执行。详见:subscription 及其适用场景

app.router(({ history }) => [routes])

使用和 ReactRouter 相同的配置,不做封装,可用 jsx 格式,也可用 javascript object 的格式支持动态路由。

详见:react-router/docs

app.start(HTMLElement, opts?)

Opts can contain the following values:

  • opts.history: default: hashHistory
  • opts.middlewares: default: []
  • opts.reducers: default: {}
  • opts.hmr: default: null

opts.history 是给路由用的 history,支持 hashHistory 和 browserHistory 。默认是 hashHistory,如果要换成 browserHistory,可以这样:

import { browserHistory } from 'dva/router';
...
app.start(container, {
  history: browserHistory,
});

opts.middlewares 是支持 redux 的 middleware,数组类型。

opts.reducers 是提供额外的 reducers,用于支持类似 redux-form 这种插件。

opts.hmr 作为用户通常不需要关心。顾名思义是拿来做 Hot Module Replacement 用的,格式为 (render, replaceReducer, restartSaga) => {},传入用于刷新 component, reducer, saga 的方法,给 HMR 用。(目前只支持 render)

HMR 的例子详见 user dashboard,代码有点多,之后会通过 babel 插件的方式让使用无感知。

尚未考虑的点

  • 插件机制
  • 动态加载
    • 这里需要考虑 reducer 和 saga 的重载,以及 subscription 的 ubsubscribe
  • dva/effects 的调用方式简化
  • connect 的封装 (和 reselect 结合,默认高性能)
  • fetch 的封装
  • ...

希望框架能委托全局dom/bom事件

在react ui组件里面要监听全局的dom事件很麻烦。
比如一个组件需要监听document点击的事件来判断是否点击的是自身, 现在的方案是要在该ui组件里实现一遍document click监听并判断, 如果一个页面上有多个不同组件有这样的监听需求,显得代码非常冗余。

不知道有没有更优雅的方法实现上面的需求。

如果框架能统一监听这些事件,并通过类似react的componentDidMounted(documentClicked)这样的钩子方法暴露给组件就好了。

并不止是click事件。

在user-dashbord这个例子里面有错误

将源码下载之后:
npm install
npm start
之后提示出错:

ERROR in ./src/index.js
Module build failed: ReferenceError: Unknown plugin "add-module-exports" specified in "/Users/hugo/Documents/workspace/react/dva-master/.babelrc" at 0, attempted to resolve relative to "/Users/hugo/Documents/workspace/react/dva-master"
    at /Users/hugo/Documents/workspace/react/dva-master/examples/user-dashboard/node_modules/babel-core/lib/transformation/file/options/option-manager.js:172:17
    at Array.map (native)
    at Function.normalisePlugins (/Users/hugo/Documents/workspace/react/dva-master/examples/user-dashboard/node_modules/babel-core/lib/transformation/file/options/option-manager.js:150:20)
    at OptionManager.mergeOptions (/Users/hugo/Documents/workspace/react/dva-master/examples/user-dashboard/node_modules/babel-core/lib/transformation/file/options/option-manager.js:224:36)
    at OptionManager.init (/Users/hugo/Documents/workspace/react/dva-master/examples/user-dashboard/node_modules/babel-core/lib/transformation/file/options/option-manager.js:338:12)
    at File.initOptions (/Users/hugo/Documents/workspace/react/dva-master/examples/user-dashboard/node_modules/babel-core/lib/transformation/file/index.js:216:65)
    at new File (/Users/hugo/Documents/workspace/react/dva-master/examples/user-dashboard/node_modules/babel-core/lib/transformation/file/index.js:137:24)
    at Pipeline.transform (/Users/hugo/Documents/workspace/react/dva-master/examples/user-dashboard/node_modules/babel-core/lib/transformation/pipeline.js:46:16)
    at transpile (/Users/hugo/Documents/workspace/react/dva-master/examples/user-dashboard/node_modules/babel-loader/index.js:38:20)
    at /Users/hugo/Documents/workspace/react/dva-master/examples/user-dashboard/node_modules/babel-loader/lib/fs-cache.js:145:18
 @ multi index

dva启动后sourcemap调试问题

用dora起服务,webpack插件调试dva的时候总是这样


是不是哪里不对

dora -p 8030 --plugins webpack
  • "dora": "0.3.x",
  • "dora-plugin-webpack": "0.6.x",
  • "babel-plugin-transform-runtime": "^6.8.0",
  • "dva": "0.0.16",
    • 浏览器版本50+

请问有没有dva的react native开发的实例?

目前做的应用网页版用的dva,感觉很赞,应用要求有app版,考虑用reactnative来开发,想用dva框架,因为rn不需要router,大部分都是导航,看到作者说dva支持reactnative,不知道是否有个简单的实例参考?

再为dva点赞!学习了很多!

关于文件结构与加载的建议

现在我们需要显式的去声明,model router 自定义middleware的加载,这部分是否可以考虑使用约定大于配置的规则。比如设置工程默认指定的model router等目录,自动扫描下面的包文件,自动调用app.model等方法加载,这样初始化的地方可以省去不少代码

dva 路由onEnter会进入多次

想做登录拦截,打算放到路由中处理
但实际路由切换时,发现onEnter进入了多次

经验证:
router的function会进入两次,第一次没有传入app,第二次传入了app
route的onEnter 会进入多次(规则为2+订阅了history的model个数)

dva 版本 :1.0.0-beta1

routerRedux.push/replace/... 没有起作用

@sorrycc @nikogu
import { routerRedux } from 'dva/router';

导入routerRedux后,replace或者push都没有作用:

  1. replace:
    routerRedux.replace('/login');
  2. push(我在effects中使用,用来设置url的查询参数,与dva样例的代码相同)
yield call(routerRedux.push, {
        query: payload,
      });

子route时,用f5刷新时,发现父route的数据没有了。

1、我的系统是左边是菜单,右边是操作区。官方例子用的是layout,我觉得麻烦,用了:

<Route path='main' component={MainPage}>
      <Route path='person' component={PersonPage}/>
</Route>

MainPage负责获得菜单数据,PersonPage负责获取人员列表,打开PersonPage后,按f5刷新时,MainPage的菜单数据为空了...

另外,顺带问下2个问题:
2、我现在开发也是用proxy,我想问问,如果正式部署的时候,我也希望前端和后端分开部署,这个时候怎么办?用fetch-jsonp?

3、dva mobile的例子,比如说,我最开始打开的是个登录页面:
app.router(() => <LoginView />);

我想登录成功后,跳转到,这个MainView是个Tabbar的容器,这个时候我应该怎么跳转?

dva 介绍

没有新概念,都是旧的。

Why dva ?

经过一段时间的自学或培训,大家应该都能理解 redux 的概念,并认可这种数据流的控制可以让应用更可控,以及让逻辑更清晰。

但随之而来通常会有这样的疑问:概念太多,并且 reducer, saga, action 都是分离的(分文件)。

这带来的问题是:

  • 编辑成本高,需要在 reducer, saga, action 之间来回切换
  • 不便于组织业务模型 (或者叫 domain model) 。比如我们写了一个 userlist 之后,要写一个 productlist,需要复制很多文件。

还有一些其他的:

  • saga 书写太复杂,每监听一个 action 都需要走 fork -> watcher -> worker 的流程
  • entry 书写麻烦
  • ...

而 dva 正是用于解决这些问题。

What's dva ?

dva 是基于现有应用架构 (redux + react-router + redux-saga 等)的一层轻量封装,没有引入任何新概念,全部代码不到 100 行。( Inspired by elm and choo. )

dva 是 framework,不是 library,类似 emberjs,会很明确地告诉你每个部件应该怎么写,这对于团队而言,会更可控。另外,除了 react 和 react-dom 是 peerDependencies 以外,dva 封装了所有其他依赖。

dva 实现上尽量不创建新语法,而是用依赖库本身的语法,比如 router 的定义还是用 react-router 的 JSX 语法的方式(dynamic config 是性能的考虑层面,之后会支持)。

他最核心的是提供了 app.model 方法,用于把 reducer, initialState, action, saga 封装到一起,比如:

app.model({
  namespace: 'products',
  state: {
    list: [],
    loading: false,
  },
  subscriptions: [
    function(dispatch) {
      dispatch({type: 'products/query'});
    },
  ],
  effects: {
    ['products/query']: function*() {
      yield call(delay(800));
      yield put({
        type: 'products/query/success',
        payload: ['ant-tool', 'roof'],
      });
    },
  },
  reducers: {
    ['products/query'](state) {
      return { ...state, loading: true, };
    },
    ['products/query/success'](state, { payload }) {
      return { ...state, loading: false, list: payload };
    },
  },
});

在有 dva 之前,我们通常会创建 sagas/products.js, reducers/products.jsactions/products.js,然后在这些文件之间来回切换。

介绍下这些 model 的 key :(假设你已经熟悉了 redux, redux-saga 这一套应用架构)

  • namespace - 对应 reducer 在 combine 到 rootReducer 时的 key 值
  • state - 对应 reducer 的 initialState
  • subscription - [email protected] 的新概念,在 dom ready 后执行,这里不展开解释,详见:A Farewell to FRP
  • effects - 对应 saga,并简化了使用
  • reducers

How to use

参考 examples:

Roadmap

  • devtool 热替换支持
  • Router 支持 Dynamic Config
  • Effects 需要支持更多的 saga 模式
  • Effects 考虑通过扩展的方式接入 thunk, promise, observable 等方案,基本目的是可以兼容 IE8
  • Component 之间还要传递 dispatch 太麻烦了,考虑下方案
  • 单元测试方案
  • More Examples: todolist, users in antd-init, popular products

FAQ

开发工具层面的支持?

除了热替换还待适配,其他的比如 redux-devtool, css livereload 等都是兼容的。

是否已经可用于生成环境?

可以。

是否包含之前 redux + redux-saga 那套应用架构的所有功能?

是的。

浏览器兼容性?

IE8 不支持,因为使用了 redux-saga 。(后面会考虑以扩展的方式在 effects 层支持 thunk, promise, observable 等)

讨论:dva-cli boilerplate structure

大家看下脚手架的目录应该如何组织? 以下是初始方案。

.
├── /mock/
├── /src/
│ ├── /components/       # React components
│ ├── /models/           # model 信息
│ ├── /routes/           # 路由 Component
│ ├── /services/         # 处理和服务器的交互
│ ├── index.html
│ ├── index.js           # 应用入口
│ ├── index.less
│ └── router.js          # 路由配置
├── package.json
├── proxy.config.js
└── webpack.config.js

详见:https://github.com/dvajs/dva-cli/tree/master/boilerplates/app

@ChrisFan @yiminghe @nikogu @afc163

讨论:插件机制

dva 提供各种 hooks,然后通过 .use() 来接入。使用方法:

const app = dva();
app.use(hmr());
app.use(log());

hooks 列表:

  • onError,effects 和 subscriptions 出错时触发,比如可以有个 dva-plugin-antd-error,用于整理处理应用的出错信息
  • onStateChange,可以让 state 和 localStorage 或者远程的 service 建立连接
  • onAction,等同于 redux middleware
  • onHmr,热替换,目前支持 components 和 routes
  • extraReducers,这个比较纠结,唯一风格不同的,不知是否有更好的命名

然后 app.start() 不再提供 middlewaresreducers 参数,这些配置本质上和 models 同级,而和 start 本身并无关系。

support redux-router

目前仅支持 react-router-redux
希望可以提供选项支持 redux-router

怎么样做页面间跳转 类似于 context.router

我现在在做的类似于从列表视图跳转到详情视图。

history.push('/roles/xxxx-xxxx-xxxx/users') 用下来有很多奇怪的问题,当然也可能和我使用的方式不对有关。

想请问官方有推荐的方式吗?

oauth2认证样例

有没有关于dva的OAuth2的样例,关于如何组织modal,如何进行权限校验?

dva的一些疑问

1、dva用了redux,这样实际上所有的组件是不是都是stateless functions?容器组件也应该是stateless functions,只不过容器组件在redux的store里面的状态变化(简单判断是不是同一个实例)之后触发刷新?stateless functions无生命周期,无后台实例,这样是不是每次都重新生成,没有diff这个动作,是不是反而没有用到reactjs的vdom。

2、在dva里面展现树,编辑树节点,由于树节点要递归生成(我原来想采用parent.children.push(child)的方式,发现不可行),那么传入的数据就由很多层,对于state的数据一般不建议多层,因为更新困难,那么树这个数据应该怎么处理好一点呢?

3、我对redux还有点迷糊的就是,redux就一个store,整个应用一直运行,数据一直放在store里面,比如说,我的web有5个列表的功能,每个列表功能上拉加载了1000条,那么5000条数据一直存在store里面?这样对内存是不是占用较多?

谢谢@sorrycc的dva!

subscriptions的适用场景?

subscriptions会在domReady后全部都执行,而且没有任何约束。
对于需登录的系统,subscriptions是不应该执行的;
或者重刷当前页面,其他页面的subscriptions 也不应该执行;
该怎么控制比较好些?在每个subscriptions里面自己再做一次判断?

app.model热加载的时候,会把执行过的dispatch在热加载后重复执行一次?

场景:app.start()渲染页面出来后,进行交互操作, 发送了一个addItem的dispatch到reducer, 改变state, 导致重新渲染视图,同时热加载app.model(a), 此时的app.model,执行的是redux的replaceReducer, 查看源码发现replaceReducer执行了dispatch({ type: ActionTypes.INIT });
而这个dispatch会将热加载之前调用过的所有dispatch-addItem(其他的dispatch也一样,只要是热加载前调用过的dispatch),全部都触发一次,为什么会是这样?

Uncaught TypeError

代码:
const OrganView = ({organ}) => { return ( <div> {organ.title} </div> ); };

错误:OrganView.jsx:6 Uncaught TypeError: Cannot read property 'title' of undefined

原因:因为我在初始状态时organ={},而这个数据是在subscription里面发一个effect action获取的,组件最开始渲染,organ={}。

我这个应该怎么写呢?

增强 demo

例如在products/vote/success的action成功后,触发一个和ProductList不同的组件的action(即另一个model的变化),包括相应 state 的变化。

English support

Hi @sorrycc you are making a really nice job here, but it is quite difficult to follow all your ideas. Is there some plan to release an English version for project's documentation?

Thanks!

1.0 roadmap

想到和收集到的需求整理如下:

  • Framework
    • 完成整体设计 (包含 api,addon/plugin/hook, 赋能和约束的权衡, config, 性能, model 和 routes 的动态加载 等等)
    • HMR 支持: components and routes
    • npm publish 前做 umd 构建
    • Test Case
    • 1-2 个 addon,比如 loading 状态的自动添加
  • Docs
    • Quick Start
    • Tutorial (一个完整的教程,通过一步步引导熟悉 dva 的所有概念)
    • Concepts
    • API
    • dva 课程开发 (面向内部全栈同学)
  • Tools
    • dva-cli (init, generate, 考虑封装 ant-tool 及其配置)
    • dva-ast

如有遗漏,请在下面评论添加。1.0 尽量把所有 api 都敲定,难免会有一些 break change 。

Ideas

没有集成在 1.0 RoadMap 里的先放这里,可能 2.0 或者之后的版本再做。

  • Framework
    • SSR Support
    • ReactNative Support
    • HMR Support: reducer, effects
    • Fetch Wrapper
    • Build Size
    • ImutableJS Support
  • Addons
    • i18n
    • auto loading status
  • Tools
    • dva-devtools
    • dva-app

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.