You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Vue 3组合式API中响应Props变更触发搜索的正确方案

Vue 3组合式API:监听搜索条件变更执行搜索

问题背景

  • 我是一名正在学习Vue的React开发者,当前有一个基于Vue 3组合式API的项目,需求是让用户输入搜索条件,点击提交后展示搜索结果。
  • 组件结构:TheSidebar组件负责输入搜索条件并提交,它会向父组件SearchView触发事件,父组件再通过props将条件传递给TheResults组件,这部分逻辑运行正常。
  • 核心需求:每当searchCriteria更新时,TheResults组件能自动使用新条件执行搜索并展示结果。
  • 在React中,我可以用useEffect钩子监听props参数,当条件更新时执行搜索并更新本地状态,但在Vue中尝试用onUpdated钩子实现时出现了无限循环——因为更新cellSites状态会触发组件更新,进而再次触发onUpdated钩子,形成循环,而且onUpdated并非专门用于监听props变更的API。
  • 我不想把搜索逻辑放到父组件SearchView的事件处理器中(避免父组件职责越界),希望保持TheResults组件的独立性,自行处理搜索逻辑。

现有代码

SearchView.vue

<script setup lang="ts">
    import { ref } from "vue";

    import type { SearchCriteria } from '@/types/SearchCriteria';
    import TheSidebar from '@/components/search/TheSidebar.vue'
    import TheResults from "@/components/search/TheResults.vue";

    const searchCriteria = ref<SearchCriteria | undefined>();

    const handleOnSearch = (criteria: SearchCriteria) => {
        searchCriteria.value = criteria;
    }
</script>

<template>
    <div class="q-main-with-sidebar">
        <TheSidebar @search="handleOnSearch" />
        <main>
            <TheResults :searchCriteria="searchCriteria" />
        </main>
    </div>
</template>

问题代码(TheResults.vue)

<script setup lang="ts">
    import { onUpdated, ref } from "vue";
    import { type SearchCriteria } from '@/types/SearchCriteria';
    import { getCellLocations } from "@/actions/cellLocations";
    import { type CellLocation } from "@/types/CellLocation";

    const cellSites = ref<{data: CellLocation[], isLoading: boolean}>({data: [], isLoading: false});

    interface IProps {
        searchCriteria: SearchCriteria | undefined;
    }

    const props = defineProps<IProps>();

    onUpdated(async () => {
        if(props.searchCriteria) {
            cellSites.value = {data: [], isLoading: true};

            let results = await getCellLocations(props.searchCriteria);
            cellSites.value = {data: results, isLoading: false};
        }
    });
</script>

<template>
    <loader v-if="cellSites.isLoading" size="small" type="pulsing" />
    <span v-else>else</span>
</template>

解决方案

在Vue 3组合式API中,对应React useEffect监听依赖的API是watch,我们可以用watch精准监听searchCriteria props的变化,只有当它变更时才执行搜索逻辑,避免无限循环。

修改后的TheResults.vue代码:

<script setup lang="ts">
    import { ref, watch } from "vue";
    import { type SearchCriteria } from '@/types/SearchCriteria';
    import { getCellLocations } from "@/actions/cellLocations";
    import { type CellLocation } from "@/types/CellLocation";

    const cellSites = ref<{data: CellLocation[], isLoading: boolean}>({data: [], isLoading: false});

    interface IProps {
        searchCriteria: SearchCriteria | undefined;
    }

    const props = defineProps<IProps>();

    // 监听searchCriteria的变化
    watch(() => props.searchCriteria, async (newCriteria) => {
        if(newCriteria) {
            // 开始加载
            cellSites.value = {data: [], isLoading: true};
            // 执行搜索
            const results = await getCellLocations(newCriteria);
            // 更新结果
            cellSites.value = {data: results, isLoading: false};
        }
    }, { immediate: true }); // immediate: true 表示组件挂载时就执行一次(如果初始有searchCriteria的话)
</script>

<template>
    <loader v-if="cellSites.isLoading" size="small" type="pulsing" />
    <span v-else>else</span>
</template>

说明

  1. watch的作用:watch会精准监听指定的响应式数据(这里是props.searchCriteria),只有当该数据发生变化时,才会执行回调函数,不会像onUpdated那样在组件任何更新时都触发。
  2. 避免无限循环:因为回调函数只在searchCriteria变更时执行,更新cellSites不会触发watch的回调(除非cellSites被监听,但这里没有),所以不会形成循环。
  3. immediate选项:如果需要组件挂载时就根据初始的searchCriteria执行一次搜索,可以保留{ immediate: true }配置;如果只需要在用户提交后(即searchCriteria从无到有/变更时)执行,可以去掉这个选项。

内容的提问来源于stack exchange,提问作者Leigh.D

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.15 09:35:15