Linke: A Decoupled Component Framework for Xianyu Frontend
Linke is a decoupled component framework for Xianyu’s frontend that separates UI (View) from business logic (Store) through a clear Interface, adopts MobX for lightweight state management, and thereby boosts code reuse, standardizes development, and cuts maintenance overhead across multiple projects.
The Xianyu frontend team faces low reusability and high maintenance cost because UI and logic are tightly coupled in component‑based development. Rapid business growth and frequent migrations (Weex → Rax 0.x → Rax 1.x) further increase the difficulty of maintaining legacy code.
The new framework, named Linke , aims to (1) improve code reusability, (2) standardize code to lower long‑term maintenance, and (3) reduce the coupling between the business layer and the technical system.
Linke separates a component into a UI layer (View) and a logic layer (Store) and isolates them with an Interface . The View handles rendering and DOM interaction, while the Store manages state and business logic. This separation enables each side to be developed and reused independently.
Current hook‑based state management in the team suffers from several problems: complex components become hard to maintain, state updates are asynchronous (e.g., const [value, setValue] = useState(0); setValue(100); console.log(value); // 0 ), and closure traps cause stale values in useEffect . Newcomers also struggle with useCallback / useMemo .
Two mainstream solutions are compared:
Redux – single source of truth, read‑only state, pure reducers; however it requires a lot of boilerplate.
MobX – action‑driven, observable state, less boilerplate and easier to adopt.
Because Xianyu’s projects rarely need the strict conventions of Redux, MobX is chosen as the Store implementation.
Linke’s core API is minimal:
observer(baseComponent, Store) – makes a View react to observable changes in its Store.
Store built‑in methods: $$set (state mutation, similar to setData ), $$setProps , $$didMount , $$unMount .
Key code examples:
export interface IMultiScrollerProps { tabs: string[]; onTabChange?(i: number): void; } export interface IMultiScroller extends IBase { readonly tabIndex: number; readonly tabSource: ITabItem[]; readonly children: any[]; onSwiperChange(i: number): void; }
import { observer } from "@ali/idlefish-linke"; import Store from './store'; import { IComponent, IComponentProps } from './interface'; function Component({items, handleLoadmore}: IComponent) { return ( <View> {items.map(item => <Text>{item.title}</Text>)} <View onClick={handleLoadmore}>load more</View> </View> ); } export default observer<IComponentProps>(Component, Store);
import { makeAutoObservable } from "@ali/idlefish-linke"; import { IComponent } from './interface'; export default class ComponentStore implements IComponent { $$set; items: any[] = []; page = 1; constructor() { makeAutoObservable(this); } $setProps(props) { /* handle props */ } $$didMount() { this.fetch(); } fetch() { mtop.request('mtop.xxx', {page}).then(d => { this.$$set('items', d.list); }); } handleLoadmore = () => { this.$$set('page', this.page++); this.fetch(); } }
By keeping View and Store loosely coupled, developers can understand component behavior by reading the Interface, reuse Stores across different Views, and combine various Stores with the same View. The framework has already been applied to multiple Xianyu projects, reducing code‑understanding cost and accelerating development.
Future work includes extending Linke to lightweight applications such as mini‑programs (Taobao Lite, WeChat Mini‑Program, Alipay Mini‑Program), which share many characteristics with H5 but have subtle differences.
Xianyu Technology
Official account of the Xianyu technology team
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.