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

如何将useState中的餐厅sections数据存入另一个useState用于过滤?

解决方案:将Sanity返回的餐厅分区数据存入useState并实现过滤功能

核心问题分析

你当前直接用let restaurantSections = restaurantData.sections存在两个关键问题:

  • 初始渲染时restaurantData是空数组,restaurantData.sections会返回undefined,触发map渲染报错
  • 当restaurantData异步更新后,restaurantSections不会自动同步,可能导致过滤逻辑使用旧数据

具体实现步骤

1. 新增分区数据的专属useState

添加专门存储餐厅分区的状态变量,初始值设为空数组:

const [restaurantSections, setRestaurantSections] = useState([]);

2. 同步更新分区数据

在获取到Sanity返回的餐厅数据后,将其中的sections同步到新状态中,同时做容错处理避免报错:

const { slug } = useParams();
const [restaurantData, setRestaurantData] = useState([]);
const [sectionsVisibility, setSectionsVisibility] = useState(true);
const [restaurantSections, setRestaurantSections] = useState([]);
const [dishesData, setDishesData] = useState([]);

useEffect(() => {
  sanityClient
    .fetch(
      `
      *[slug.current == "${slug}"] {
        ...,
        sections[] -> {
          ...,
          dishes[] ->
        }
      }`
    )
    .then((data) => {
      setRestaurantData(data[0]);
      // 用可选链+默认值避免data[0]为空时的报错
      setRestaurantSections(data[0]?.sections || []);
    });
}, [slug]);

3. 调整过滤函数逻辑

过滤时直接使用restaurantSections状态变量,确保拿到最新数据,同时修正逻辑为返回分区下的餐品(而非整个分区对象):

const filter = (name) => {
  const targetSection = restaurantSections.find((section) => section.name === name);
  // 容错处理,避免找不到对应分区时返回undefined
  setDishesData(targetSection?.dishes || []);
};

4. 优化列表渲染的容错性

渲染分区列表前先判断数据是否存在,避免初始加载时的报错:

{restaurantSections.length > 0 ? (
  restaurantSections.map((section) => (
    <li
      key={section._id}
      onClick={() => {
        // setSectionsVisibility(false);
        filter(section.name);
        console.log(section.name)
      }}
    >
      <div>
        {section.image ? (
          <img src={urlFor(section.image).url()} alt="food" />
        ) : (
          <img src={foodImg} alt="food" />
        )}
        <h1>{section.name}</h1>
        <span>
          <HiArrowSmRight size={20} className="arrowIcon" />
        </span>
      </div>
    </li>
  ))
) : (
  <li>加载中...</li>
)}
</ul>

注:你原代码中restaurantData.image应为section.image,每个分区的图片属于自身而非餐厅整体。


更优实现思路

不需要单独维护restaurantSections状态,直接基于restaurantData结合useMemo优化性能,减少状态变量的冗余:

const { slug } = useParams();
const [restaurantData, setRestaurantData] = useState(null);
const [selectedSectionName, setSelectedSectionName] = useState(null);
const [sectionsVisibility, setSectionsVisibility] = useState(true);

useEffect(() => {
  sanityClient
    .fetch(
      `
      *[slug.current == "${slug}"] {
        ...,
        sections[] -> {
          ...,
          dishes[] ->
        }
      }`
    )
    .then((data) => setRestaurantData(data[0]));
}, [slug]);

// 用useMemo缓存过滤结果,避免每次渲染重复计算
const dishesData = useMemo(() => {
  if (!restaurantData?.sections) return [];
  if (!selectedSectionName) return []; // 可根据需求改为返回所有餐品
  const targetSection = restaurantData.sections.find(section => section.name === selectedSectionName);
  return targetSection?.dishes || [];
}, [restaurantData, selectedSectionName]);

// 点击事件直接设置选中的分区名称
const handleSectionClick = (name) => {
  // setSectionsVisibility(false);
  setSelectedSectionName(name);
};

这种方式减少了状态变量的维护成本,利用useMemo避免不必要的计算,逻辑更简洁高效。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.05 22:25:17