V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
fanck0605
V2EX  ›  Vue.js

Vue 组件 props 改变时,如何阻止多余的 render

  •  
  •   fanck0605 · 2021-08-20 12:17:06 +08:00 · 1447 次点击
    这是一个创建于 970 天前的主题,其中的信息可能已经有所发展或是发生改变。

    这是一个 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>
                );
            };
        }
    });
    
    fanck0605
        1
    fanck0605  
    OP
       2021-08-20 12:29:25 +08:00
    调用它们的父组件
    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>
    );
    }
    });
    banricho
        2
    banricho  
       2021-08-26 09:38:20 +08:00
    试试用 toRef 代替 toRefs

    const postLang = toRef(props, 'postLang')
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   我们的愿景   ·   实用小工具   ·   4279 人在线   最高记录 6543   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 30ms · UTC 05:27 · PVG 13:27 · LAX 22:27 · JFK 01:27
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.