Performance Optimization of Complex List Pages in Taro3
This article examines performance bottlenecks in a Taro3-based hotel list page, presents measurement data, and details multiple optimization techniques—including preload API, setData reduction, node count trimming, animation refactoring, data flattening, virtual list enhancements, custom wrapper usage, native components, and React.memo—to significantly improve rendering speed and user experience.
The project’s continuous iteration led to a growing codebase, and the Taro3 runtime showed serious performance drawbacks on complex list pages, causing long white‑screen times and poor user experience.
Measurements on a multi‑function hotel list revealed high setData call counts and rendering times (e.g., first entry: 7 setData calls, 2404 ms render; pull‑down update: 3 calls, 1903 ms; filter update: 2 calls, 1758 ms). These figures highlighted three main issues: excessive initial load time, sluggish filter updates, and stuttered infinite scrolling.
3.1 Preload API – By invoking Taro.preload before navigation, network requests for the complex list are started early, reducing perceived latency by about 300‑400 ms. Example:
// Page A
const query = new Query({ /* ... */ })
Taro.preload({
RequestPromise: requestPromiseA({ data: query })
})
// Page B
componentDidMount() {
Taro.getCurrentInstance().preloadData?.RequestPromise?.then(res => {
this.setState(this.processResData(res.data))
})
}Testing showed the preloaded list loaded noticeably faster than the original.
3.2 Optimizing setData – The setData API was split into fewer, larger updates and combined small state changes, cutting the first‑load setData calls from 7 to 3 and shaving ~200 ms (≈9% reduction). A summary table illustrated the improvement.
3.3 Reducing Node Count – Following WeChat guidelines, the page was kept under 1,000 nodes and a depth under 30 layers. Selective rendering was applied: filter components are only instantiated when expanded, and deep nesting was avoided.
3.4 Filter Animation Refactor – The original keyframes‑based fade‑in caused a flash and jank. It was replaced with a CSS transition:
.filter-wrap {
transform: translateY(-100%);
transition: none;
}
.filter-wrap.active {
transform: translateY(0);
transition: transform .3s ease-in;
}This eliminated the flash and smoothed the animation.
3.4.2 Maintaining a Simple State – Complex filter objects were flattened to a key‑value map, allowing O(1) updates. Example of flattening and usage:
{
"a": { "subs": [{ "a1": { "subs": [{ "id": 1 }] } }] },
"b": { "subs": [{ "id": 2 }] }
}
// Flattened version
{
"1": { "id": 1, "name": "汉庭", "includes": [], "excludes": [] },
"2": { /* ... */ }
}
const flattenFilters = data => { /* ... */ }
const filtersSelected = {}
const onClickFilterItem = item => {
const flatItem = flatFilters[item.id]
if (filtersSelected[flatItem.id]) delete filtersSelected[flatItem.id]
else {
filtersSelected[flatItem.id] = flatItem
// handle excludes, etc.
}
this.setState({ filtersSelected })
}The flattening reduced filter‑update latency by 5‑18%.
3.5 Long‑List Optimizations – A virtual list renders only visible items, and the next page’s data is pre‑loaded into memory to avoid pull‑down stalls. This cut the pull‑down update time from ~1900 ms to ~836 ms (≈56% reduction).
3.6 CustomWrapper – Using custom-wrapper isolates component rendering, turning page‑wide setData into component‑level updates. Example markup:
<custom-wrapper is="custom-wrapper">
#shadow-root
<view class="list"></view>
</custom-wrapper>This isolation yielded an additional 200‑300 ms speed gain on low‑end devices.
3.7 Native Component Usage – Re‑implementing list items with native mini‑program components bypassed Taro’s diffing layer, dramatically reducing setData calls (from 3 to 1) and rendering time (from 1903 ms to 836 ms). The trade‑off is duplicated styling and loss of Taro APIs.
3.8 React.memo – Wrapping pure functional components with React.memo prevents unnecessary re‑renders:
const MyComponent = React.memo(function MyComponent(props) {
/* render using props */
})
export default React.memo(MyComponent, areEqual)This shallow comparison further trims render cycles.
Conclusion – By combining preload, setData consolidation, node reduction, animation tweaks, data flattening, virtual list strategies, custom wrappers, native components, and React.memo , the complex list page’s load and interaction latency were substantially lowered, delivering a smoother user experience while still monitoring for future improvements.
Ctrip Technology
Official Ctrip Technology account, sharing and discussing growth.
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.