这是一个 Vue3 编写的异步加载的博文列表的组件,通过传入一个 postLang 来筛选不同语言的博文。
当 postLang 发生变化时,这个组件会被渲染两次,第一次时 postLang 发生变化时立即渲染,第二次是异步请求完成时刷新博文列表。
这个组件 render 时并没有直接引用 props 里的变量,所以第一次渲染时我的组件中没有任何需要更新的内容, 这次渲染显然是多余的,那么我们可以阻止它进行吗
Lang: Vue
BlogPost: create
BlogPost: render // 显示正在加载...
BlogPost: render // 显示 Lang 为 Vue 的博文
Lang: Vuex
BlogPost: render // 无用的 render
BlogPost: render // 显示 Lang 为 Vuex 的博文
export const BlogPost = defineComponent({
name: 'BlogPost',
props: {
postLang: {
type: String,
default: 'Vue'
}
},
setup(props) {
console.log(BlogPost.name + ': create');
const {postLang} = toRefs(props);
const postList = ref<{ title: string }[]>([]);
onMounted(async () => postList.value = await fetchPostList(postLang.value));
watch(postLang, async () => postList.value = await fetchPostList(postLang.value));
return () => {
console.log(BlogPost.name + ': render');
const renderContent = () => {
if (postList.value.length === 0) {
return <div>正在加载中...</div>;
} else {
return postList.value.map(post => <BlogPostItem title={post.title}/>);
}
};
return (
<div>
{renderContent()}
</div>
);
};
}
});
下面来看一个更加清晰的例子,这一次我们在 setup 函数中完全不用 props,显然组件的内部状态完全不受 props 干扰,但是当入参 props 改变时,我们查看日志可以发现,组件仍然会重新 render 。而如果把 props 换成是 Vue Ref (非组合式 API 的 data ),如果只要 render 函数中没有调用这个 ref,那么组件就不会因为 ref 的改变而被重新 render,那么对于 props,Vue 是否可以有同样的优化,来消除这些多余的 render 呢。
Lang: Vue
BlogPostNotUseProps: create
BlogPostNotUseProps: render // 显示正在加载...
BlogPostNotUseProps: render // 显示 Lang 为 Vue 的博文(写死了)
Lang: Vuex
BlogPostNotUseProps: render // 无用的 render
export const BlogPostNotUseProps = defineComponent({
name: 'BlogPostNotUseProps',
props: {
postLang: {
type: String,
default: 'Vue'
}
},
setup(props) {
console.log(BlogPostNotUseProps.name + ': create');
// const {postLang} = toRefs(props);
const postList = ref<{ title: string }[]>([]);
onMounted(async () => postList.value = await fetchPostList('Vue'));
// watch(postLang, async () => postList.value = await fetchPostList(postLang.value));
return () => {
console.log(BlogPostNotUseProps.name + ': render');
const renderContent = () => {
if (postList.value.length === 0) {
return <div>正在加载中...</div>;
} else {
return postList.value.map(post => <BlogPostItem title={post.title}/>);
}
};
return (
<div>
{renderContent()}
</div>
);
};
}
});
这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。
V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。
V2EX is a community of developers, designers and creative people.