基于条件的默认渲染

Default render based on conditions

我正在设计一个基本的 login/sign up 界面。登录和注册 UI 驻留在它们自己的组件中,并且每个都包含一个 link 到彼此(使用 <Link to> 以防用户在显示注册时已经有一个帐户,或者想要创建显示登录时的帐户)。

我的结构如下:

index.tsx

ReactDOM.render(
  <MemoryRouter>
    <Routes>
      <Route path="/" element={<App />} >
        <Route path="signup" element={<Signup />} />
        <Route path="login" element={<Login />} />
      </Route>
    </Routes >
  </MemoryRouter >,
  document.getElementById('root')
);

App.tsx

function App() {
  return (
    <div className="App">
      <UserControl />
      <Outlet />
    </div>
  );
}

UserControl.tsx

function UserControl() {
///snip unrelated code

    if (!isLoggedIn && !userHasNeverLoggedInBefore) {
        return (<Signup />)
    } else if (!isLoggedIn) {
        return (<Login />)
    } else {
        return (<Functionality />
        )
    }
}

打开“/”时,我想决定是显示登录、注册还是功能。我也想 links 在登录和注册中互相。

用我目前的方法,我看到 UI 两次 - 我假设一个来自 App.tsx 中的 <UserControl>,另一个来自 <Outlet> .如何有条件地只渲染一次?

我正在使用 React Router 6。

您正在渲染它们两次。我建议在 UserControl 中使用重定向将用户推送到呈现正确 LoginSignup 组件的正确路径。

示例:

function UserControl() {
  // ... snip unrelated code

  if (!isLoggedIn) {
    return (
      <Navigate
        to={userHasNeverLoggedInBefore ? "/login" : "/signup"}
        replace
      />
    );
  }
  return <Functionality />;
}

更新

This seems to render the first component correctly, however now the links between login and sign up are broken (clicking does nothing). For context, this is how I set up links in the component : <Link to="/signup">Sign up</Link> and similarly for the sign up component.

我认为这里的问题是您正在创建一个 quasi-AuthWrapper 组件,该组件重定向到它作为子项呈现的路由。当用我的解决方案测试你的代码时,它变成了一个无限渲染循环。完全不理想。

然后我建议将 UserControl 转换为 full-blown AuthWrapper 组件。

  1. <Functionality /> 替换为 <Outlet /> 组件。

    function UserControl() {
      // ... snip unrelated code
    
      if (!isLoggedIn) {
        return (
          <Navigate
            to={userHasNeverLoggedInBefore ? "/login" : "/signup"}
            replace
          />
        );
      }
      return <Outlet />;
    }
    
  2. 将路线移至 App。使用UserControl组件作为布局组件保护路由渲染<Functionality />。将登录和注册路由 移出身份验证包装器的

    function App() {
      return (
        <div className="App">
          <Routes>
            <Route element={<UserControl />}>
              <Route path="/" element={<Functionality />} />
            </Route>
            <Route path="/signup" element={<Signup />} />
            <Route path="/login" element={<Login />} />
          </Routes>
        </div>
      );
    }