流式渲染
除了利用流的响应式数据来做渲染,fluth 提供了强大的流式渲染 render$ 功能,可以实现元素级渲染或者块级渲染,整体效果类似 signal 或者 block signal 的渲染。
元素级渲染
tsx
import { defineComponent, onUpdated } from "vue";
import { $, effect$ } from "fluth-vue";
export default defineComponent(
() => {
const name$ = $("hello");
onUpdated(() => {
console.log("Example 组件更新");
});
return effect$(() => (
<div>
<div>
名字:{name$.render$()}
</div>
<button onClick={() => name$.set((v) => v + " world")}>更新</button>
</div>
);
},
{
name: "Example",
},
);
点击更新按钮更新文案的时候,不会触发组件的 onUpdated 生命周期。
块级渲染
tsx
import { defineComponent, onUpdated } from "vue";
import { $, effect$ } from "fluth-vue";
export default defineComponent(
() => {
const info$ = $({ name: "", age: 0, address: "" });
onUpdated(() => {
console.log("Example 组件更新");
});
return effect$(() => (
<div>
<div>用户信息</div>
{user$.render$((v) => (
<div>
<div>名字:{v.name}</div>
<div>年龄:{v.age}</div>
<div>地址:{v.address}</div>
</div>
))}
<button onClick={() => user$.set((v) => (v.age += 1))}>
更新用户信息
</button>
</div>
);
},
{
name: "Example",
},
);
点击更新按钮后,只会触发 user$.render$ 内部的重新渲染,不会触发组件的 onUpdated 生命周期。
对比
采用 fluth render$ 和 ref 渲染的对比:
tsx
/* eslint-disable @typescript-eslint/no-unused-vars */
import { defineComponent, onUpdated, h } from "vue";
import { $, effect$ } from "fluth-vue";
export default defineComponent(
() => {
const user$ = $({ name: "", age: 0, address: "" });
const order$ = $({ item: "", price: 0, count: 0 });
return effect$(() => (
<div class="card-light">
<div> example component </div>
<div>render time: {Date.now()}</div>
<section style={{ display: "flex", justifyContent: "space-between" }}>
{/* use$ emit data only trigger render content update*/}
{user$.render$((v) => (
<div key={Date.now()} class="card">
<div>user$ render</div>
<div>name:{v.name}</div>
<div>age:{v.age}</div>
<div>address:{v.address}</div>
<div>render time: {Date.now()}</div>
</div>
))}
{/* order$ emit data only trigger render content update*/}
{order$.render$((v) => (
<div key={Date.now()} class="card">
<div>order$ render</div>
<div>item:{v.item}</div>
<div>price:{v.price}</div>
<div>count:{v.count}</div>
<div>render time: {Date.now()}</div>
</div>
))}
</section>
<div class="operator">
<button class="button" onClick={() => user$.set((v) => (v.age += 1))}>
update user$ age
</button>
<button
class="button"
onClick={() => order$.set((v) => (v.count += 1))}
>
update order$ count
</button>
</div>
</div>
));
},
{
name: "streamingRender",
},
);
tsx
/* eslint-disable @typescript-eslint/no-unused-vars */
import { defineComponent, ref, h } from "vue";
import { $, effect$ } from "fluth-vue";
export default defineComponent(
() => {
const user = ref({ name: "", age: 0, address: "" });
const order = ref({ item: "", price: 0, count: 0 });
return effect$(() => (
<div class="card-light" key={Date.now()}>
<div> example component </div>
<div>render time: {Date.now()}</div>
<section style={{ display: "flex", justifyContent: "space-between" }}>
<div key={Date.now()} class="card">
<div>user ref render</div>
<div>name:{user.value.name}</div>
<div>age:{user.value.age}</div>
<div>address:{user.value.address}</div>
<div>render time: {Date.now()}</div>
</div>
<div key={Date.now()} class="card">
<div>order ref render</div>
<div>item:{order.value.item}</div>
<div>price:{order.value.price}</div>
<div>count:{order.value.count}</div>
<div>render time: {Date.now()}</div>
</div>
</section>
<div class="operator">
<button class="button" onClick={() => (user.value.age += 1)}>
update user age
</button>
<button class="button" onClick={() => (order.value.count += 1)}>
update order count
</button>
</div>
</div>
));
},
{
name: "RefRender",
},
);
tsx
/* eslint-disable @typescript-eslint/no-unused-vars */
import { defineComponent, ref, h } from "vue";
import { $, effect$ } from "../../core/useFluth/index";
export default defineComponent(
() => {
const user$ = $({ name: "", age: 0, address: "" });
const order = ref({ item: "", price: 0, count: 0 });
return effect$(() => (
<div class="card-light" key={Date.now()}>
<div> example component </div>
<div>render time: {Date.now()}</div>
<section style={{ display: "flex", justifyContent: "space-between" }}>
{/* use$ emit data only trigger render content update*/}
{user$.render$((v) => (
<div key={Date.now()} class="card">
<div>user$ render</div>
<div>name:{v.name}</div>
<div>age:{v.age}</div>
<div>address:{v.address}</div>
<div>render time: {Date.now()}</div>
</div>
))}
<div key={Date.now()} class="card">
<div>order ref render</div>
<div>item:{order.value.item}</div>
<div>price:{order.value.price}</div>
<div>count:{order.value.count}</div>
<div>render time: {Date.now()}</div>
</div>
</section>
<div class="operator">
<button class="button" onClick={() => user$.set((v) => (v.age += 1))}>
update user$ age
</button>
<button class="button" onClick={() => (order.value.count += 1)}>
update order count
</button>
</div>
</div>
));
},
{
name: "MixRender",
},
);
流式渲染效果
example component
render time: 1756111673825
user$ render
name:
age:0
address:
render time: 1756111673826
order$ render
item:
price:0
count:0
render time: 1756111673826
ref 渲染效果
example component
render time: 1756111673826
user ref render
name:
age:0
address:
render time: 1756111673826
order ref render
item:
price:0
count:0
render time: 1756111673826
流式 + ref 混合渲染效果
example component
render time: 1756111673826
user$ render
name:
age:0
address:
render time: 1756111673826
order ref render
item:
price:0
count:0
render time: 1756111673826