【问题标题】:React-Router v4 shared layout re-rendersReact-Router v4 共享布局重新渲染
【发布时间】:2017-10-17 03:05:39
【问题描述】:

我知道以前有人问过这个问题,但我一直对此有疑问。

我遇到的问题是,当我使用类似 页面布局 的组件来包装我的路线时,此页面布局在更改路径时会重新渲染。

在 react-router v3 中我做了这样的事情:

<Router history={this.props.history}>
  <Route path="/">
    <IndexRedirect to="/Dossiers" />
    <Route path="/Dossiers" component={MainLayout}>
      <IndexRoute component={DossiersPage} />
      <Route path="/Dossiers/:dossierId/:title" component={DossierDetailsPage} />
    </Route>
  </Route>
</Router>

当移动路径时,这不会重新渲染MainLayout 组件(通过在MainLayout 中放置一些东西很容易检查)。

现在,在 react-router v4 中我已经尝试了几种方法:

但是,我尝试过的所有解决方案似乎都重新渲染了 MainLayout 组件,基本上导致 state 重置为其初始值。


tldr;如何在react-router v4 中创建一个包装组件,它在更改路径时不会重新渲染

【问题讨论】:

    标签: reactjs react-router react-router-dom


    【解决方案1】:

    这里是 React Router v4 的正确解决方案,如 here 所述

    所以基本上你需要使用 render 方法来渲染布局并像这样包装你的组件:

    <Router>
      <Switch>
        <Route path={ROUTES.LOGIN} render={props => 
          <LoginLayout {...props}>
            <Login {...props} />
          </LoginLayout>
        } />
        <Route path={ROUTES.REGISTER} render={props => 
          <LoginLayout {...props}>
            <Register {...props} />
          </LoginLayout>
        } />
    
        <Route path="*" component={NotFound} />
      </Switch>
    </Router>
    

    这不会在您更改路线时导致重新渲染布局。

    当您有许多不同布局的不同组件时,您可以继续在路由配置数组中定义它们,例如 issue I linked 中的示例:

    const routes = [
      { path: '/',
        exact: true,
        component: Home
      },
      { path: '/about',
        component: About,
      },
      { path: '/cart',
        component: Three,
      }
    ]
    
    <Router>
      <Switch>
        {routes.map({ path, exact, component: Comp } => (
          <Route path={path} exact={exact} render={(props) => (
            <LayoutWithSidebarAndHeader {...props}>
              <Comp {...props}/>
            </LayoutWithSidebarAndHeader>
          )}/>
        ))}
        <Route component={Error404}/>
      </Switch>
    </Router>
    

    【讨论】:

      【解决方案2】:

      我整理了一个代码框示例,说明我如何使用“页面布局”类型的组件。它使用 React Router v4.1.2。

      https://codesandbox.io/s/Vmpy1RzE1

      正如您在问题中所描述的那样,正如马特的回答中所描述的那样,MainLayout 组件包装了路由。

      <BrowserRouter>
        <MainLayout>
          <Switch>
            <Route path="/" exact component={Home} />
            <Route path="/about" exact component={About} />
          </Switch>
        </MainLayout>
      </BrowserRouter>
      

      当我浏览应用程序时,MainLayout 组件确实会重新呈现,从某种意义上说,render 是由 React 调用的。但是,MainLayout 组件永远不会被卸载,因此状态永远不会重新初始化。

      我在我的示例周围放置了一些console.logs 来展示这一点。我的MainLayout 看起来像这样:

      export default class MainLayout extends React.Component {
        state = {
          layoutCreatedOn: Date(),
        };
      
        componentDidMount() {
          //This will not fire when we navigate the app.
          console.log('layout did mount.');
        }
      
        componentWillUnmount() {
          //This won't fire,
          // because our "shared page layout" doesn't unmount.
          console.log('layout will unmount');
        }
      
        render() {
          //This does fire every time we navigate the app.
          // But it does not re-initialize the state.
          console.log('layout was rendered');
      
          return (
            <div styles={styles}>
              <h5>
                Layout created: {this.state.layoutCreatedOn}
              </h5>
              <Sidebar />
              {this.props.children}
            </div>
          );
        }
      }
      

      当您点击应用程序时,您会看到一些内容。

      1. componentDidMount 只触发一次。
      2. componentWillUnmount 永远不会触发。
      3. render 每次导航时都会触发。
      4. 尽管如此,我的layoutCreatedOn 属性在我浏览应用程序的同时显示。状态在页面加载时被初始化,并且永远不会重新初始化。

      【讨论】:

      • 这将为您的所有路线进行布局。如何仅为特定路线创建布局?
      【解决方案3】:

      您不再需要IndexRedirect,而是只需将所有路由包装在您的MainLayout 组件中,例如:

      <Router history={this.props.history}>
        <Switch>
          <MainLayout>
            <Route path="/" component={DossiersPage}/>
            <Route path="/Dossiers/:dossierId/:title" component={DossierDetailsPage} />
          </MainLayout>
        </Switch>
      </Router>
      

      【讨论】:

      • 使用这个重新渲染 MainLayout 组件
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2022-01-11
      • 1970-01-01
      • 2022-07-04
      • 2018-02-10
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多