
这是一个 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') |