5

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

 3 years ago
source link: https://www.v2ex.com/t/796983
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

V2EX  ›  Vue.js

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

  fanck0605 · 18 小时 0 分钟前 · 330 次点击

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

About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK