Frontend Development 14 min read

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.

ByteDance Data Platform
ByteDance Data Platform
ByteDance Data Platform
How HookStore Revamps DataWind’s Frontend Data Flow with Redux and Hooks

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&lt;IReduxState&gt;(state => ..)

, which conflicted with modern

async/await

patterns.

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

&lt;VizQueryWind/&gt;

to create isolated data‑flow scopes, and use a single hook

useVizQuery

to 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

useVizQuery

call 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‑redux

store via a typed

useStore

hook:

<code>const useStore = reduxUseStore as () => Store&lt;IReduxStore&gt;
function App() {
  const store = useStore()
  const onClick = useCallback(() => {
    console.log(store.getState().userName)
  }, [])
}
</code>

Multi‑Instance Support

Each

&lt;VizQueryWind/&gt;

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.

frontendMigrationTypeScriptReduxReactHooksData Flow
ByteDance Data Platform
Written by

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.

0 followers
Reader feedback

How this landed with the community

login Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.