Implementing mini-async-dva: Adding async/await Support to DVA
This article examines the limitations of the original DVA framework, proposes a mini‑async‑dva fork that adds async/await support to model effects, and details its implementation—including store management, dynamic model registration, and asynchronous component loading—while providing full code comparisons.
Background The DVA framework is widely used in React front‑end projects, but its development has stalled and its model effects rely on generators, lacking async/await support.
Why build a new wheel To improve developer experience, the author created mini‑async‑dva , a lightweight version that retains DVA’s workflow while enabling async/await in effects.
Comparison
1. Routing files
## dva
const Foo = dynamic({
app,
models: () => [import('./models/foo')],
component: () => import('./pages/Foo'),
});
...
...
## mini-async-dva
import Bar from './pages/Bar';
...
...2. Models
## dva
export default {
namespace: 'foo',
state: { list: [] },
effects: {
*fetchList({ payload }, { call }) {
yield call(delay, 1000);
}
}
};
## mini-async-dva
export default {
namespace: 'foo',
state: { list: [] },
effects: {
async fetchList(payload, updateStore) {
await delay();
}
}
};3. View layer
## dva
import React from 'react';
import { connect } from 'dva';
@connect(state => state.bar)
class Bar extends React.Component { ... }
export default Bar;
## mini-async-dva
import React from 'react';
import model from '@/model';
@model('bar')
class Bar extends React.Component { ... }
export default Bar;Implementation
1. Store management The wheel keeps Redux for state, but adds dynamic model registration via a custom action @@redux/register . Effects are stored in an effectsMap for later execution.
const effectsMap = {};
const store = createStore((state, action) => {
const { type, payload = {} } = action;
const { namespace, effects, initalState, updateState } = payload;
if (type === '@@redux/register') {
effectsMap[namespace] = effects;
return Object.assign({}, state, { [namespace]: initalState });
}
if (type === '@@redux/update') {
return Object.assign({}, state, { [namespace]: Object.assign({}, state[namespace], updateState) });
}
if (type.includes('/') && !type.includes('@@redux/INIT')) {
const [sliceNameSpace, effect] = type.split('/');
if (effectsMap[sliceNameSpace] && effectsMap[sliceNameSpace][effect]) {
executeAsyncTask(state, sliceNameSpace, effectsMap[sliceNameSpace][effect], payload);
}
}
return state;
}, {});2. Async loading AsyncComponent loads required models asynchronously, registers them, and renders the wrapped view only after all models are loaded.
import { useStore } from 'react-redux';
function AsyncComponent({ deps, children, ...rest }) {
const store = useStore();
const [modelLoaded, setModelLoaded] = useState(!Array.isArray(deps) && deps.length === 0);
useEffect(() => {
if (!modelLoaded) {
Promise.all(deps.map(dep => runImportTask(dep))).then(() => setModelLoaded(true));
}
}, []);
function runImportTask(dep) {
if (!store.getState().hasOwnProperty(dep)) {
return new Promise((resolve, reject) => {
import(`models/${dep}.js`).then(module => {
const { namespace, state: initalState = {}, effects } = module.default;
store.dispatch({
type: '@@redux/register',
payload: { effects, initalState, namespace: namespace || dep }
});
resolve();
}).catch(reject);
});
}
}
if (modelLoaded) {
return <>{React.createElement(children, rest)};
}
return null;
}3. State binding The model decorator collects model dependencies, wraps the component with connect , and nests it inside AsyncComponent to ensure models are loaded before rendering.
function model(...deps) {
return function wrapComponent(target) {
const cacheRender = connect(state => {
return deps.reduce((mapState, dep) => {
mapState[dep] = state[dep];
return mapState;
}, {});
}, null)(target);
return props => (
{cacheRender}
);
};
}Conclusion The mini‑async‑dva library provides a concise solution for adding async/await support to DVA effects, simplifies routing by using native React components, and maintains dynamic model registration, with the full source available on GitHub.
Fulu Network R&D Team
Providing technical literature sharing for Fulu Holdings' tech elite, promoting its technologies through experience summaries, technology consolidation, and innovation sharing.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.