programing

레이아웃 페이지 또는 페이지당 여러 구성 요소와 함께 반응 라우터 사용

prostudy 2022. 3. 11. 22:40
반응형

레이아웃 페이지 또는 페이지당 여러 구성 요소와 함께 반응 라우터 사용

기존 프로젝트에 리액션 라우터를 추가한다.

현재 모델은 서브 내비게이션용 내비게이션 구성 요소와 메인 구성 요소를 포함하는 루트 구성 요소로 전달된다.

내가 찾은 리액션 라우터의 예로는 하위 구성요소가 하나뿐인데, 둘 다에서 레이아웃 코드를 반복하지 않고 여러 하위 구성요소를 변경하는 가장 좋은 방법은 무엇인가?

만약 내가 당신을 정확히 이해했다면, 당신은 당신의 안에 여러 구성요소를 정의 할 것이다.Route. 다음과 같이 사용할 수 있다.

// think of it outside the context of the router, if you had pluggable
// portions of your `render`, you might do it like this
<App children={{main: <Users/>, sidebar: <UsersSidebar/>}}/>

// So with the router it looks like this:
const routes = (
  <Route component={App}>
    <Route path="groups" components={{main: Groups, sidebar: GroupsSidebar}}/>
    <Route path="users" components={{main: Users, sidebar: UsersSidebar}}>
      <Route path="users/:userId" component={Profile}/>
    </Route>
  </Route>
)

class App extends React.Component {
  render () {
    const { main, sidebar } = this.props;
    return (
      <div>
        <div className="Main">
          {main}
        </div>
        <div className="Sidebar">
          {sidebar}
        </div>
      </div>
    )
  }
}

class Users extends React.Component {
  render () {
    return (
      <div>
        {/* if at "/users/123" `children` will be <Profile> */}
        {/* UsersSidebar will also get <Profile> as this.props.children,
            so its a little weird, but you can decide which one wants
            to continue with the nesting */}
        {this.props.children}
      </div>
    )
  }
}

사이드바 예제 앱도 확인해 보십시오.

편집: @Luiz의 설명에 따라:

라우터(v3)의 최신 버전에서 구성 요소는 소품 개체의 루트에 있음

자:

const { main, sidebar } = this.props.children;

다음이 됨:

const { main, sidebar } = this.props;

편집: 리액터 v4에서 다음과 같이 수행할 수 있다(새로운 문서에 제공된 예에 따름).

import React from 'react'
import {
  BrowserRouter as Router,
  Route,
  Link
} from 'react-router-dom'

// Each logical "route" has two components, one for
// the sidebar and one for the main area. We want to
// render both of them in different places when the
// path matches the current URL.
const routes = [
  { path: '/',
    exact: true,
    sidebar: () => <div>home!</div>,
    main: () => <h2>Home</h2>
  },
  { path: '/bubblegum',
    sidebar: () => <div>bubblegum!</div>,
    main: () => <h2>Bubblegum</h2>
  },
  { path: '/shoelaces',
    sidebar: () => <div>shoelaces!</div>,
    main: () => <h2>Shoelaces</h2>
  }
]

const SidebarExample = () => (
  <Router>
    <div style={{ display: 'flex' }}>
      <div style={{
        padding: '10px',
        width: '40%',
        background: '#f0f0f0'
      }}>
        <ul style={{ listStyleType: 'none', padding: 0 }}>
          <li><Link to="/">Home</Link></li>
          <li><Link to="/bubblegum">Bubblegum</Link></li>
          <li><Link to="/shoelaces">Shoelaces</Link></li>
        </ul>

        {routes.map((route, index) => (
          // You can render a <Route> in as many places
          // as you want in your app. It will render along
          // with any other <Route>s that also match the URL.
          // So, a sidebar or breadcrumbs or anything else
          // that requires you to render multiple things
          // in multiple places at the same URL is nothing
          // more than multiple <Route>s.
          <Route
            key={index}
            path={route.path}
            exact={route.exact}
            component={route.sidebar}
          />
        ))}
      </div>

      <div style={{ flex: 1, padding: '10px' }}>
        {routes.map((route, index) => (
          // Render more <Route>s with the same paths as
          // above, but different components this time.
          <Route
            key={index}
            path={route.path}
            exact={route.exact}
            component={route.main}
          />
        ))}
      </div>
    </div>
  </Router>
)

export default SidebarExample

여기서 새로운 Ract Router v4 문서를 확인하십시오. https://reacttraining.com/react-router/

2019 +

간단하고 깨끗한 방법으로 이를 수행하고 악의적인 재렌딩을 방지할 수 있는 방법은 다음과 같다(반응 라우터 v5에서 테스트, 반응 라우터 v4에서 확인 필요).

       <Switch>
         <Route exact path={["/route1/:id/:token", "/"]}>
          <Layout1>
            <Route path="/route1/:id/:token" component={SetPassword} />
            <Route exact path="/" component={SignIn} />
          </Layout1>
        </Route>
        <Route path={["/route2"]}>
          <Layout2>
            <Route path="/route2" component={Home} />
          </Layout2>
        </Route>
      </Switch>

다음과 같이 리팩터링할 수 있다.

const routes = [
  {
    layout:Layout1,
    subRoutes:[
      {
        path:"/route1/:id/:token",
        component:SetPassword
      },
      {
        exact:true,
        path:"/",
        component:SignIn
      },
    ]
  },
  {
    layout:Layout2,
    subRoutes:[
      {
        path:"/route2",
        component:Home
      },
    ]
  }
];

다음 항목 포함:

      <Switch>
        {routes.map((route,i)=>
          <Route key={i} exact={route.subRoutes.some(r=>r.exact)} path={route.subRoutes.map(r=>r.path)}>
            <route.layout>
              {route.subRoutes.map((subRoute,i)=>
                <Route key={i} {...subRoute} />
              )}
            </route.layout>
          </Route>
        )}
      </Switch>

세바스티앙의 대답에 덧붙여 말하자면, 이것은 찾지 못한 경로와 역동적인 서브루트를 포함한 나에게 효과가 있는 것 같다.아래 예들은 나를 만든다.LayoutAuthenticated그리고LayoutAnonymous동일한 레이아웃을 사용하는 경로 내의 모든 경로 변경에 대해 한 번만 렌더링하십시오.또한 다음 항목도 추가됨PageSettings이 아키텍처 내에 중첩된 경로를 표시하는 예제.이것이 다른 사람들에게 도움이 되기를!

(예: TypeScript 포함)

const publicRoutes = [
  {
    key: "login",
    path: "/login",
    component: PageLogin,
    exact: true
  },
  {
    key: "signup",
    path: "/signup",
    component: PageSignup,
    exact: true
  },
  {
    key: "forgot-password",
    path: "/forgot-password",
    component: PageForgotPassword,
    exact: true
  }
];

const privateRoutes = [
  {
    key: "home",
    path: "/",
    component: PageHome,
    exact: true
  },
  {
    key: "settings",
    path: "/settings",
    component: PageSettings, // sub routing is handled in that component
    exact: false // important, PageSettings is just a new Router switch container
  }
];
// Routes.tsx

<Router>
  <Switch>
    <Route exact path={["/", "/settings", "/settings/*"]}>
      <LayoutAuthenticated>
        <Switch>
          {privateRoutes.map(privateRouteProps => (
            <PrivateRoute {...privateRouteProps} />
          ))}
        </Switch>
      </LayoutAuthenticated>
    </Route>

    <Route exact path={["/login", "/signup", "/forgot-password"]}>
      <LayoutAnonymous>
        <Switch>
          {publicRoutes.map(publicRouteProps => (
            <PublicRoute {...publicRouteProps} />
          ))}
        </Switch>
      </LayoutAnonymous>
    </Route>

    <Route path="*">
      <LayoutAnonymous>
        <Switch>
          <Route component={PageNotFound} />
        </Switch>
      </LayoutAnonymous>
    </Route>
  </Switch>
</Router>
// LayoutAnonymous.tsx

import React from 'react';

export const LayoutAnonymous: React.FC<{}> = props => {
  return (
    <div>
      {props.children}
    </div>
  )
}

// LayoutAuthenticated.tsx

import React from 'react';
import { MainNavBar } from '../components/MainNavBar';
import { MainContent } from '../components/MainContent';

export const LayoutAuthenticated: React.FC<{}> = props => {
  return (
    <>
      <MainNavBar />
      <MainContent>
        {props.children}
      </MainContent>
    </>
  )
}


// PrivateRoute.tsx

import React from "react";
import {
  Route,
  Redirect,
  RouteProps
} from "react-router-dom";
import { useSelector } from "react-redux";

interface Props extends RouteProps {}

export const PrivateRoute: React.FC<Props> = props => {
  const isAuthenticated: boolean = useSelector<any, any>((stores) => stores.auth.isAuthenticated);

  const { component: Component, ...restProps } = props;

  if (!Component) return null;

  return (
    <Route
      {...restProps}
      render={routeRenderProps =>
        isAuthenticated ? (
          <Component {...routeRenderProps} />
        ) : (
          <Redirect
            to={{
              pathname: "/login",
              state: { from: routeRenderProps.location }
            }}
          />
        )
      }
    />
  )
}
// PublicRoute.tsx


import React from "react";
import { Route, RouteProps, Redirect } from "react-router-dom";
import { useSelector } from "react-redux";

interface Props extends RouteProps {}

export const PublicRoute: React.FC<Props> = props => {
  const isAuthenticated: boolean = useSelector<any, any>((stores) => stores.auth.isAuthenticated);
  const { component: Component, ...restProps } = props;

  if (!Component) return null;

  return (
    <Route
      {...restProps}
      render={routeRenderProps => (
        !isAuthenticated ? (
          <Component {...routeRenderProps} />
        ) : (
          <Redirect
            to={{
              pathname: "/",
              state: { from: routeRenderProps.location }
            }}
          />
        )
      )}
    />
  )
}

// PageSettings.tsx

import React from "react";
import { LinkContainer } from "react-router-bootstrap";
import Button from "react-bootstrap/Button";
import {
  Switch,
  useRouteMatch,
  Redirect,
  Switch
} from "react-router-dom";

import { PrivateRoute } from "../../routes/PrivateRoute";
import { PageSettingsProfile } from "./profile";
import { PageSettingsBilling } from "./billing";
import { PageSettingsAccount } from "./account";

export const PageSettings = () => {
  const { path } = useRouteMatch();

  return (
    <div>
      <h2>Settings</h2>

      <Redirect strict from={path} to={`${path}/profile`} />

      <LinkContainer to={`${path}/profile`}>
        <Button>Profile</Button>
      </LinkContainer>
      <LinkContainer to={`${path}/billing`}>
        <Button>Billing</Button>
      </LinkContainer>
      <LinkContainer to={`${path}/account`}>
        <Button>Account</Button>
      </LinkContainer>

      <Switch>
        <PrivateRoute path={`${path}/profile`} component={PageSettingsProfile} />
        <PrivateRoute path={`${path}/billing`} component={PageSettingsBilling} />
        <PrivateRoute path={`${path}/account`} component={PageSettingsAccount} />
      </Switch>
    </div>
  );
};

이 부품은 JSX를 반환하는 기능이 될 수 있다.

  <Route>
    <Route path="/" component={App}>
      <IndexRoute component={Home} />
      <Route path="Invite" component={()=>(<div><Home/><Invite/></div>)} />
    </Route>
  </Route>

"너무 복잡하게 만드는 대신 라우터 태그 내부에 두 개의 스위치 문을 직접 사용할 수 있다"고 말했다.

    <div className= {classes.root}>
      <CssBaseline></CssBaseline>
      <Router>
      <Switch>
        <Route path="/" exact component={Header}></Route>
        <Route path="/login" component={Login}></Route>
      </Switch>
      <Switch>
        <Route path="/" exact component={Checkout}></Route>
      </Switch>
      </Router> 
    </div>
This will solve your problem of having two components one below the other.

참조URL: https://stackoverflow.com/questions/33062830/using-react-router-with-a-layout-page-or-multiple-components-per-page

반응형