2

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

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

在 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

4

3 回答 3

3

我整理了一个代码框示例,说明我如何使用“页面布局”类型的组件。它使用 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当我浏览应用程序时,组件会重新呈现,在renderReact 调用的意义上。但是,MainLayout组件永远不会被卸载,因此状态永远不会重新初始化。

console.log在我的示例周围放置了一些 s 来展示这一点。我的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属性显示的时间与我浏览应用程序的时间相同。该状态在页面加载时被初始化,并且永远不会重新初始化。
于 2017-07-20T22:05:39.260 回答
0

这是此处所述的 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>

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

当您有许多具有许多不同布局的不同组件时,您可以继续在路由配置数组中定义它们,就像我链接的问题中的示例一样:

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>
于 2019-12-03T12:28:28.237 回答
0

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

<Router history={this.props.history}>
  <Switch>
    <MainLayout>
      <Route path="/" component={DossiersPage}/>
      <Route path="/Dossiers/:dossierId/:title" component={DossierDetailsPage} />
    </MainLayout>
  </Switch>
</Router>
于 2017-05-17T15:07:06.760 回答