Memo
缓存渲染组件,仅在监听的依赖项变化时重新渲染。
API 参考
语法
<Memo watch={watchSource} deep={boolean?}>
{(value) => ReactNode}
</Memo>
属性
watch
: 要监听的数据源(store、函数或任何值)deep
(可选): 启用深度相等检查以处理嵌套对象children
: 接收监听值的渲染函数
示例
昂贵组件优化
import { createStore, Memo } from "zenbox";
const dataStore = createStore({
items: Array.from({ length: 1000 }, (_, i) => ({
id: i,
value: Math.random(),
name: `Item ${i}`,
})),
threshold: 0.5,
});
function ExpensiveVisualization() {
return (
<div>
<h2>数据可视化</h2>
<Memo
watch={() => ({
items: dataStore.value.items,
threshold: dataStore.value.threshold,
})}
>
{({ items, threshold }) => {
console.log("渲染昂贵可视化..."); // 仅在依赖项变化时输出
// 昂贵计算
const processedItems = items
.filter((item) => item.value > threshold)
.map((item) => ({
...item,
processed: Math.pow(item.value, 2) * Math.sin(item.id),
}))
.sort((a, b) => b.processed - a.processed);
return (
<div className="expensive-chart">
<h3>处理后的项目 ({processedItems.length})</h3>
{processedItems.slice(0, 20).map((item) => (
<div key={item.id} className="chart-item">
{item.name}: {item.processed.toFixed(4)}
</div>
))}
</div>
);
}}
</Memo>
</div>
);
}
多 Store 缓存渲染
const cartStore = createStore({
items: [
{ id: 1, name: "电脑", price: 999, quantity: 1, category: "电子产品" },
{ id: 2, name: "鼠标", price: 25, quantity: 2, category: "电子产品" },
],
});
const settingsStore = createStore({
currency: "¥",
taxRate: 0.08,
discountPercent: 0.1,
});
function CartSummary() {
return (
<Memo
watch={() => ({
items: cartStore.value.items,
settings: settingsStore.value,
})}
>
{({ items, settings }) => {
console.log("渲染复杂购物车摘要..."); // 仅在依赖项变化时输出
// 复杂计算
const subtotal = items.reduce(
(sum, item) => sum + item.price * item.quantity,
0
);
const discount = subtotal * settings.discountPercent;
const tax = (subtotal - discount) * settings.taxRate;
const total = subtotal - discount + tax;
return (
<div className="cart-summary">
<div className="cart-items">
{items.map((item) => (
<div key={item.id} className="cart-item">
<span>{item.name}</span>
<span>
{item.quantity} × {settings.currency} {item.price}
</span>
</div>
))}
</div>
<div className="cart-totals">
<div>
小计: {settings.currency} {subtotal.toFixed(2)}
</div>
<div>
折扣: -{settings.currency} {discount.toFixed(2)}
</div>
<div>
税费: {settings.currency} {tax.toFixed(2)}
</div>
<div>
<strong>
总计: {settings.currency} {total.toFixed(2)}
</strong>
</div>
</div>
</div>
);
}}
</Memo>
);
}
最佳实践
✅ 用于昂贵计算 - 适合包含大量计算的组件
// Good - 昂贵计算受益于缓存
<Memo watch={() => dataStore.value}>
{(data) => {
const expensiveResult = heavyComputation(data);
return <ComplexChart data={expensiveResult} />;
}}
</Memo>
❌ 不要用于频繁变化的数据
// Bad - 计数器频繁变化,使用缓存帮助不大
<Memo watch={() => counterStore.value.count}>
{(count) => <div>{count}</div>}
</Memo>
✅ 明确依赖项 - 只监听影响渲染输出的数据
// Good - 明确依赖项
<Memo
watch={() => ({ items: store.value.items, threshold: store.value.threshold })}
>
{({ items, threshold }) => (
<ProcessedList items={items} threshold={threshold} />
)}
</Memo>
何时使用 Memo vs 其他选项
使用场景 | 推荐方式 | 原因 |
---|---|---|
昂贵计算 | <Memo> | 缓存避免重复计算 |
简单 store 访问 | usePick 或 useStoreValue | 简单情况下开销更少 |
副作用 | useWatch 或 useWatchEffect | Memo 用于渲染,不适合副作用 |
频繁变化的数据 | 普通组件 | 数据频繁变化时缓存无效 |
相关文档
<Watch>
- 无缓存的响应式渲染组件useComputed
- 响应式更新的计算值useStoreValue
- 同步 store 最新状态