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

Vue3:修改filteredData为何会改动原始Store的countriesData?如何解决

问题:修改filteredData时意外改动了countriesData

在Vue项目中,我们期望countriesData仅通过异步请求初始化一次后不再变动,filteredData用于存储搜索筛选后的结果。但执行搜索逻辑后,发现countriesData也被修改成了筛选后的单个数据,只有注释掉filteredData.value = [countriesData.value[i]]这行代码,countriesData才会保持原样。

Store代码

import { ref } from "vue";

// Store for all data
export const countriesData = ref();
export const isLoading = ref(true);

async function getData() {
    try {
        isLoading.value = true;
        const response = await fetch("https://restcountries.com/v3.1/all");
        const data = await response.json();
        countriesData.value = data;
    } catch (error) {
        console.error("error", error);
    } finally {
        isLoading.value = false;
    }
}

getData();

// Store for filtered data
export const filteredData = ref(countriesData);

搜索组件代码

<script setup>
import { ref } from "vue";
import { countriesData, filteredData } from "../../store/store";

const searchValue = ref("");

function handleSubmit(e) {
    e.preventDefault();
console.log(countriesData.value.length);

    for (let i = 0; i < countriesData.value.length; i++) {
        console.log(countriesData.value.length);
        if (
            countriesData.value[i].name.common.toLowerCase() ===
            searchValue.value.toLowerCase().trim()
        ) {
            filteredData.value = [countriesData.value[i]];
            // setError(false);
            searchValue.value = "";
            return;
        } else {
            // setError(true);
        }
    }
}
</script>

问题原因

核心问题出在Store里的filteredData初始化代码:

export const filteredData = ref(countriesData);

这里直接把countriesData这个ref对象传给了filteredData的ref构造函数,导致两个ref指向了同一个引用值。当你修改filteredData.value时,本质上是在修改countriesData.value的内容,因为它们共享同一个数组引用。

解决方案

1. 修正Store中filteredData的初始化逻辑

将filteredData初始化为独立的空数组,在异步请求完成后复制一份countriesData的数据进去:

import { ref } from "vue";

// Store for all data
export const countriesData = ref();
export const isLoading = ref(true);
export const filteredData = ref([]); // 初始化为空数组

async function getData() {
    try {
        isLoading.value = true;
        const response = await fetch("https://restcountries.com/v3.1/all");
        const data = await response.json();
        countriesData.value = data;
        filteredData.value = [...data]; // 浅拷贝数据,创建新数组
        // 如果数据存在嵌套对象,需要深拷贝的话用下面这行:
        // filteredData.value = JSON.parse(JSON.stringify(data));
    } catch (error) {
        console.error("error", error);
    } finally {
        isLoading.value = false;
    }
}

getData();

2. 优化搜索逻辑(可选)

用数组的find方法替代for循环,代码更简洁:

<script setup>
import { ref } from "vue";
import { countriesData, filteredData } from "../../store/store";

const searchValue = ref("");

function handleSubmit(e) {
    e.preventDefault();
    const searchTerm = searchValue.value.toLowerCase().trim();
    
    // 查找匹配的国家
    const matchedCountry = countriesData.value.find(country => 
        country.name.common.toLowerCase() === searchTerm
    );

    if (matchedCountry) {
        // 如果需要避免后续修改filteredData中的对象影响原数据,可深拷贝
        filteredData.value = [matchedCountry];
        // filteredData.value = [JSON.parse(JSON.stringify(matchedCountry))];
        searchValue.value = "";
        // setError(false);
    } else {
        // setError(true);
        // 无匹配时可清空筛选结果或保留原数据
        // filteredData.value = [];
    }
}
</script>

内容的提问来源于stack exchange,提问作者Ninety9Balloons

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.30 06:00:20