React-Router v4共享布局重新渲染

时间:2017-05-17 15:00:37

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

我知道之前已经问过这个问题,但我一直有这个问题。

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

在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 中,我尝试了几种方法:

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

tldr; 如何在state中创建包装组件,在更改路径时不会重新呈现

3 个答案:

答案 0 :(得分:2)

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

https://codesandbox.io/s/Vmpy1RzE1

正如您在问题中描述的那样,正如Matt的回答所述,MainLayout组件包裹了路径。

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

在导航应用程序时,MainLayout组件确实重新呈现,因为React调用了render。但是,MainLayout组件永远不会卸载,因此状态永远不会重新初始化。

我在示例中放置了一些console.log来展示这一点。我的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. 每次导航时,
  4. render都会触发。
  5. 尽管如此,我的layoutCreatedOn属性显示了我浏览应用的同一时间。页面加载时初始化状态,并且从不重新初始化。

答案 1 :(得分:0)

您不再需要MainLayout,而只需将所有路线包裹在<Router history={this.props.history}> <Switch> <MainLayout> <Route path="/" component={DossiersPage}/> <Route path="/Dossiers/:dossierId/:title" component={DossierDetailsPage} /> </MainLayout> </Switch> </Router> 组件中,例如:

for beg in pd.date_range('2013-12-21', '2017-05-17', freq='90D'):
    smpl = merged.loc[beg:beg + pd.Timedelta('20D')]
    ...

答案 2 :(得分:0)

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

因此,基本上,您需要使用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>