
本文介绍如何将多层嵌套的州-城市 json 数据扁平化,并基于动态城市名(如 url 参数)精准检索出城市名称、所属州全称、州缩写 id 及描述信息,适用于 react 单页应用中的城市详情页开发。
本文介绍如何将多层嵌套的州-城市 json 数据扁平化,并基于动态城市名(如 url 参数)精准检索出城市名称、所属州全称、州缩写 id 及描述信息,适用于 react 单页应用中的城市详情页开发。
在处理类似美国各州与下属城市组成的嵌套 JSON 数据时,直接使用 map().filter() 容易产生二维数组(如 [[], [{...}], []]),导致后续取值困难且逻辑冗余。更优雅、可维护的方案是先扁平化再过滤——利用 Array.prototype.flatMap() 将深层结构一次性展开为统一的“城市条目”数组,每个条目都携带完整上下文(州名、州 ID、城市名、描述)。
以下为完整实现步骤:
✅ 步骤 1:扁平化原始数据
对 stateNames 数组执行 flatMap,遍历每个州对象,再遍历其 places 数组,为每个城市构造一个融合了州级信息的新对象:
import stateNames from './states.json';
const allPlaces = stateNames.flatMap(({ state, id, places }) =>
places.map((place) => ({
stateName: state.trim(), // 清理首尾空格(如 "Illinois " → "Illinois")
stateId: id,
city: place.city.trim(), // 同样清理城市名空格
description: place.description,
}))
);
? 注意:
.trim()至关重要——原始数据中"Elgin "带有尾部空格,若不清理将导致'Elgin ' !== 'Elgin'匹配失败。
✅ 步骤 2:按城市名动态过滤
在组件中读取路由参数,并在扁平数组中精确匹配(注意大小写敏感,如需忽略大小写可改用 city.toLowerCase() === cityname.toLowerCase()):
import { useParams } from 'react-router-dom';
const CityDetailsPage = () => {
const { cityname } = useParams();
// 安全兜底:若 URL 中无 cityname,返回空数组或重定向
if (!cityname) return <p>城市未指定</p>;
const matches = allPlaces.filter(
(place) => place.city === cityname
);
// 若无匹配项,友好提示
if (matches.length === 0) {
return <p>未找到城市 "{cityname}" 的相关信息。</p><div class="aritcle_card flexRow artxards">
<div class="artcardd flexRow">
<a class="aritcle_card_img" rel="nofollow" href="/xiazai/skill11765" title="Expanso yaml-to-json"><img
src="https://img.php.cn/upload/skill/001/246/273/6adaf20dbae7c507.jpg" alt="Expanso yaml-to-json" onerror="this.onerror='';this.src='/static/lhimages/moren/morentu.png'" ></a>
<div class="aritcle_card_info flexColumn">
<a rel="nofollow" href="/xiazai/skill11765" title="Expanso yaml-to-json" class="overflowclass">Expanso yaml-to-json</a>
<p class="overflowclass">使用 Expanso Edge 管道将 YAML 输入转换为 JSON 格式。</p>
</div>
<a rel="nofollow" href="/xiazai/skill11765" title="Expanso yaml-to-json" class="aritcle_card_btn flexRow flexcenter"><b></b><span>下载</span>
</a>
</div>
</div>;
}
return (
{matches.map((place, index) => (
<div key="{index}" classname="city-detail">
<h2>{place.city}, {place.stateId}</h2>
<p><strong>所属州:</strong>{place.stateName}</p>
<p><strong>简介:</strong>{place.description}</p>
</div>
))}
>
);
};
export default CityDetailsPage;
✅ 输出示例(访问 /city/Elgin)
<div class="city-detail"> <h2>Elgin, IL</h2> <p><strong>所属州:</strong>Illinois</p> <p><strong>简介:</strong>elgin-description</p> </div>
⚠️ 关键注意事项
-
性能考量:
flatMap + filter是一次性预处理,适合静态或低频更新的数据;若数据量极大(>10k 条城市),建议构建 Map 索引(如new Map)提升 O(1) 查询效率。 -
空格与大小写:务必对
city和state字段调用.trim(),并在比较前统一大小写策略。 -
类型安全(TypeScript):推荐定义接口增强健壮性:
interface Place { city: string; description: string; stateName: string; stateId: string; } const allPlaces: Place[] = /* ... */;
通过扁平化预处理 + 精确过滤,你不仅能简洁获取所需字段,还为未来支持模糊搜索、多城市批量查询、分页渲染等扩展功能打下坚实基础。









