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

Shopify Polaris侧边导航激活项选中异常问题及优化方案咨询

Shopify Polaris 导航激活状态异常修复方案

问题根源

你遇到的点击两次才显示激活状态的问题,主要来自两个原因:

  1. 状态更新违反不可变原则:原代码中直接修改了selected原数组(selected[index] = true),React依赖状态的引用变化触发重新渲染,直接修改原数组会导致状态更新不被检测,渲染异常。
  2. 状态与路由不同步:点击导航时先更新状态再跳转路由,但React状态更新是异步的,路由跳转后组件可能重新渲染,初始状态会覆盖未完成更新的状态;同时直接访问路由或通过浏览器前进后退时,状态也不会自动同步。

高效修复方案(路由同步版)

以下方案通过绑定路由路径管理激活状态,同时监听路由变化自动同步,彻底解决点击延迟和路由不同步问题:

import React, { Fragment, useState, useEffect } from "react";
import { Frame, Navigation, Page } from "@shopify/polaris";
import { GiftCardMinor } from "@shopify/polaris-icons"; // 替换为实际所需图标
import { useNavigate, useLocation } from "react-router-dom";

const LeftNavigation = ({ pageTitle, loading, children }: any) => {
  const navigate = useNavigate();
  const location = useLocation();
  // 用当前路由路径作为激活状态标识,更直观易维护
  const [activePath, setActivePath] = useState(location.pathname);

  // 监听路由变化,自动同步激活状态
  useEffect(() => {
    setActivePath(location.pathname);
  }, [location.pathname]);

  // 统一管理导航项,新增/修改只需调整此数组
  const navItems = [
    {
      label: "one",
      icon: GiftCardMinor,
      path: "/one",
    },
    {
      label: "two",
      icon: GiftCardMinor,
      path: "/two",
    },
  ];

  const handleNavClick = (path: string) => {
    setActivePath(path);
    navigate(path);
  };

  return (
    <Fragment>
      <Frame
        navigation={
          <div style={{ marginTop: "4rem" }}>
            <Navigation location="/">
              <Navigation.Section
                title="nav items"
                items={navItems.map(item => ({
                  ...item,
                  selected: activePath === item.path,
                  onClick: () => handleNavClick(item.path),
                }))}
              />
            </Navigation>
          </div>
        }
      >
        <Page title={pageTitle} loading={loading}>
          {children}
        </Page>
      </Frame>
    </Fragment>
  );
};

export default LeftNavigation;

方案优势

  • 状态管理更直观:用路由路径代替数组索引,新增导航项无需修改状态初始化逻辑
  • 路由自动同步:不管是点击导航、直接访问路由还是浏览器前进后退,激活状态都会自动更新
  • 遵循React状态原则:通过设置新的字符串值更新状态,避免直接修改原数组导致的更新异常
  • 易维护:导航项统一数组管理,修改、扩展更便捷

动态导航实现方案(适用于接口获取导航项)

如果你的导航项是从后端接口动态获取的,可使用以下方案:

import React, { Fragment, useState, useEffect } from "react";
import { Frame, Navigation, Page } from "@shopify/polaris";
import { GiftCardMinor } from "@shopify/polaris-icons";
import { useNavigate, useLocation } from "react-router-dom";

// 模拟从接口获取导航项的异步函数
const fetchDynamicNavItems = async () => {
  // 实际场景替换为接口请求逻辑
  return await new Promise(resolve => {
    setTimeout(() => {
      resolve([
        { label: "one", icon: GiftCardMinor, path: "/one" },
        { label: "two", icon: GiftCardMinor, path: "/two" },
        { label: "three", icon: GiftCardMinor, path: "/three" },
      ]);
    }, 500);
  });
};

const LeftNavigation = ({ pageTitle, loading, children }: any) => {
  const navigate = useNavigate();
  const location = useLocation();
  const [activePath, setActivePath] = useState(location.pathname);
  const [navItems, setNavItems] = useState<Array<{label: string; icon: any; path: string}>>([]);
  const [isNavLoading, setIsNavLoading] = useState(true);

  // 同步路由状态
  useEffect(() => {
    setActivePath(location.pathname);
  }, [location.pathname]);

  // 加载动态导航项
  useEffect(() => {
    const loadNavItems = async () => {
      const items = await fetchDynamicNavItems();
      setNavItems(items);
      setIsNavLoading(false);
    };
    loadNavItems();
  }, []);

  const handleNavClick = (path: string) => {
    setActivePath(path);
    navigate(path);
  };

  // 导航加载中显示占位
  if (isNavLoading) {
    return <div style={{padding: "1rem"}}>加载导航中...</div>;
  }

  return (
    <Fragment>
      <Frame
        navigation={
          <div style={{ marginTop: "4rem" }}>
            <Navigation location="/">
              <Navigation.Section
                title="nav items"
                items={navItems.map(item => ({
                  ...item,
                  selected: activePath === item.path,
                  onClick: () => handleNavClick(item.path),
                }))}
              />
            </Navigation>
          </div>
        }
      >
        <Page title={pageTitle} loading={loading}>
          {children}
        </Page>
      </Frame>
    </Fragment>
  );
};

export default LeftNavigation;

方案说明

  • 通过异步请求获取导航项,加载过程中显示过渡状态
  • 同样保持路由与激活状态的自动同步,动态项也能正确显示选中状态
  • 类型定义增强代码健壮性(可根据实际项目调整)

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.07 15:25:10