dva: Elm-style React/Redux Framework

2.4.1 · abandoned · verified Sun Apr 19

Dva is a lightweight, Elm-style front-end framework designed for building single-page applications by integrating React, Redux, React Router, and Redux Saga into a cohesive development experience. It simplifies state management and side effects through a declarative model system and streamlined data flow, aiming to reduce boilerplate typically associated with Redux setups. The package's last stable release, version 2.4.1, dates back to 2018, with subsequent beta versions for 2.6.0 released in late 2019. The project currently exhibits an abandoned release cadence, with no further stable releases or active development beyond 2019. Its key differentiators include an opinionated, "batteries-included" approach that pre-configures major React ecosystem libraries and its model-centric architecture for managing application state and logic.

Common errors

Warnings

Install

Imports

Quickstart

Demonstrates a basic Dva application setup with a model (state, reducers, effects, subscriptions) and routing using `dva/router`, showing how to connect a component to the Redux store.

import dva, { connect } from 'dva';
import React from 'react';
import ReactDOM from 'react-dom';
import { Router, Route, Switch } from 'dva/router';

// 1. Initialize
const app = dva();

// 2. Model
app.model({
  namespace: 'count',
  state: { current: 0 },
  reducers: {
    add(state) { return { current: state.current + 1 }; },
    minus(state) { return { current: state.current - 1 }; },
  },
  effects: {
    *addAsync(action, { call, put }) {
      yield call(() => new Promise(resolve => setTimeout(resolve, 1000)));
      yield put({ type: 'add' });
    },
  },
  subscriptions: {
    setup({ dispatch, history }) {
      history.listen(({ pathname }) => {
        if (pathname === '/count') {
          console.log('Entered count page');
          dispatch({ type: 'add' }); // Initial increment when entering
        }
      });
    },
  },
});

// 3. View
function CountPage({ count, dispatch }) {
  return (
    <div>
      <h2>Count: {count.current}</h2>
      <button onClick={() => dispatch({ type: 'add' })}>+</button>
      <button onClick={() => dispatch({ type: 'minus' })}>-</button>
      <button onClick={() => dispatch({ type: 'addAsync' })}>Add Async</button>
    </div>
  );
}

const ConnectedCountPage = connect(({ count }) => ({ count }))(CountPage);

// 4. Router
app.router(({ history }) => (
  <Router history={history}>
    <Switch>
      <Route path="/" exact component={() => <div>Home Page <br/><a href="/count">Go to Count</a></div>} />
      <Route path="/count" component={ConnectedCountPage} />
    </Switch>
  </Router>
));

// 5. Start
// Ensure you have a div with id="root" in your HTML
app.start('#root');

view raw JSON →