这是一个 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>
);
};
}
});
1
fanck0605 OP 调用它们的父组件
export default defineComponent({ components: {}, data() { return { lang: 'Vue' }; }, render() { console.log('Lang: ' + this.lang); return ( <div> <input v-model={this.lang}/> <div>Lang: {this.lang}</div> <BlogPost postLang={this.lang}/> <BlogPostNotUseProps postLang={this.lang}/> </div> ); } }); |
2
banricho 2021-08-26 09:38:20 +08:00
试试用 toRef 代替 toRefs
const postLang = toRef(props, 'postLang') |