反应如何使有条件呈现的导航持久化

问题描述

我正在学习 React 并且正在创建一个 React 桌面应用程序,其中侧边导航必须根据用户的当前位置(由应用程序主体中的标准导航按钮确定)而改变。

可在此处访问该应用程序:https://codesandbox.io/s/conditional-navigation-di8t5?file=/pages/Start.jsx

我能够在用户浏览应用程序时有条件地呈现导航选项。参见示例:从“开始”到“页面 A”,再到“页面 B”。问题是当他们移回以前的位置时,导航也会恢复。我希望它是这样的,一旦用户到达页面 B 并返回页面 A,页面 B 仍然可以在侧边导航中访问。

从研究来看,使用 React Context API 似乎是最好的解决方案。是这种情况,还是我缺少更简单的方法?谢谢。

解决方法

您可以采用c0m1t中提到的使用useLocation来跟踪当前位置的方法。

为了能够始终如一地跟踪位置以及出于其他更多的组织原因,我还建议您稍微更改应用程序结构。

我认为当前结构的一个问题是 Layout 是每个页面组件的子级。相反,我认为这个组件更适合作为页面的父级,而不是让每个页面呈现一个 Layout 组件。这同样适用于您的 Header 组件。

我建议将您的 App.js 文件更改为如下所示:

function App() {
  return (
    <ThemeProvider theme={theme}>
      <Header />
      <Layout>
        <Switch>
          <Route exact path="/" component={Start} />
          <Route exact path="/page-A" component={PageA} />
          <Route exact path="/page-B" component={PageB} />
          <Route exact path="/page-C" component={PageC} />
        </Switch>
      </Layout>
    </ThemeProvider>
  );
}

我也不认为您需要为每个屏幕使用不同的 Menu 组件。

您可以改为拥有一个通用的 Menu 组件并在您的 Layout 组件中呈现此组件:

const Layout = (props) => {
  return (
    <React.Fragment>
      <Grid container>
        <Grid item xs={3} className="side-nav">
          <Menu />
        </Grid>
        <Grid item xs={9} className="main">
          <Box p={4}>{props.children}</Box>
        </Grid>
      </Grid>
    </React.Fragment>
  );
};

然后您可以将 Menu 组件更改为:

const pageLocations = ["/page-A","/page-B","/page-C"];
const pages = ["Page A","Page B","Page C"];

const Menu = () => {
  const location = useLocation();
  const [locations,setLocations] = React.useState([]);

  React.useEffect(() => {
    const currentPath = location.pathname;
    if (!locations.includes(currentPath)) {
      setLocations([...locations,currentPath]);
    }
  },[location,locations,setLocations]);

  return (
    <Box>
      <MenuList>
        {pages.map((page,i) => {
          return (
            <MenuItem
              key={i}
              to={pageLocations[i]}
              className={locations.includes(pageLocations[i]) ? "" : "deactive"}
              component={NavLink}
            >
              {page}
            </MenuItem>
          );
        })}
      </MenuList>
    </Box>
  );
};

所以方法是从菜单中跟踪之前访问过的所有页面。位置映射到每个菜单项,我们可以根据已访问的所有位置和映射到菜单项的位置检查是否应显示菜单项。

此答案不处理您从 /page-A 之类的特定页面的网址而不是 / 开始的情况。


sandbox example