How HookStore Revamps DataWind’s Frontend Data Flow with Redux and Hooks
This article explains how DataWind’s frontend team replaced the outdated Dva‑based data flow with a new Redux‑plus‑hook solution called HookStore, detailing the pain points of complex initialization, legacy async syntax, tight module coupling, and showing migration steps, code examples, and benefits such as multi‑instance support and OpenAPI decoupling.
Problems with the Existing Dva‑Based Flow
DataWind, a platform for massive‑scale self‑service data analysis, originally used the Umi scaffolding with Dva, whose syntax is outdated and tightly coupled, causing module‑level breakage during refactoring.
Complex Initialization Templates
Initialising the data flow required verbose boilerplate code, as shown in the following snippet:
<code>export const getInitialState = (): IState => {...}
const model = combineModel({...}, analysisModels, dynamicFieldModels)
const undoableActionTypes = [...]
function withCancelable<T>(effect: [T, any]): [T, any]
function withCancelable<T>(effect: T): T
function withCancelable(effect) {...}
model.effects.init = withCancelable(model.effects.init)
function vizQueryEnhance<T extends IState>(model: Model): Model {
const { namespace, effects, reducers } = model
const modelActionTypes = Object.keys({...})
const enhancedReducer = getUndoEnhancer<T>(model as any, {...} as UndoableOptions<T>)
return {...}
}
const { dispatchAction, getLoading, putAction } = getModuleInfo(...)
const enhancedModel = vizQueryEnhance(model as any)
export default enhancedModel
export const myModel = {
action: dispatchAction,
innerAction: putAction,
getLoading,
getState: getModuleGetter<IMyModelState>(namespace)
}
</code>Outdated Async Syntax
The project relied on custom async handling via
cmd.call(fn, args)and
cmd.select<IReduxState>(state => ..), which conflicted with modern
async/awaitpatterns.
Effect Calls to Reducer Are Cumbersome
Because reducers are pure and synchronous, side‑effects were forced into separate effect modules, leading to verbose calls and string‑based references that lacked type safety.
Data‑Flow Coupling Across Modules
Modules such as visual query, dashboards, and data sets all shared a single global Dva store, making independent deployment or multi‑instance scenarios impossible.
Introducing HookStore
HookStore is a new data‑flow solution built on Redux + React Hooks . It provides two creation functions from
@dp/wind:
<code>import { createMiddleware, createWind } from '@dp/wind'</code>Developers wrap parts of the UI with
<VizQueryWind/>to create isolated data‑flow scopes, and use a single hook
useVizQueryto both read state and dispatch actions.
Hook‑Based Actions and Variables
Actions are written as regular hooks inside
createMiddleware, allowing async/await and any other React Hook APIs. The same
useVizQuerycall returns selectors for variables and bound methods, eliminating the need for
connect,
mapStateToProps, or manual generic parameters.
Migrating Class Components
Class components that cannot use hooks are wrapped with a functional component (FCWrapper) or gradually refactored to function components, dramatically simplifying the codebase.
Instant Value Retrieval
For cases where an immediate snapshot is required, developers can use the native
react‑reduxstore via a typed
useStorehook:
<code>const useStore = reduxUseStore as () => Store<IReduxStore>
function App() {
const store = useStore()
const onClick = useCallback(() => {
console.log(store.getState().userName)
}, [])
}
</code>Multi‑Instance Support
Each
<VizQueryWind/>creates an independent store, so multiple visual‑query applications can run side‑by‑side without interfering with each other.
Decoupling OpenAPI
OpenAPI now registers capabilities via
useExternal. Applications simply call the exposed functions through
useVizQuery, keeping the API layer independent of the underlying data‑flow implementation.
Migration Strategy
Because the old Dva models are tightly interwoven, a successful migration requires a “big‑bang” approach: start with modules that have no dependencies, use window‑level shims for missing pieces, and progressively replace all Dva models with HookStore equivalents.
Conclusion
HookStore offers a concise, type‑safe, and multi‑instance‑friendly data‑flow mechanism that resolves the pain points of Dva, improves developer experience, and aligns with modern React practices.
ByteDance Data Platform
The ByteDance Data Platform team empowers all ByteDance business lines by lowering data‑application barriers, aiming to build data‑driven intelligent enterprises, enable digital transformation across industries, and create greater social value. Internally it supports most ByteDance units; externally it delivers data‑intelligence products under the Volcano Engine brand to enterprise customers.
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.