根据网址更新网页内容,不要重新加载整个网页

时间:2017-05-04 15:45:24

标签: javascript reactjs react-router

上下文

我正在使用ReactRouter 4。

我有以下基础路由器

<Router>
    <Route exact path="/" component={HomePage} />
    <Route
      path="/courses/:courseName"
      render={(props) => {
        switch (props.match.params) { 
          case '1':
            return React.createElement(
              fetch('courses/1/')(CoursePage),
              props,
              null
            );
          case '2':
            return React.createElement(
              fetch('courses/2/')(CoursePage),
              props,
              null
            );
          default:
            return <FourOFour />
        }
      }}
    />
</Router>

fetch('courses/NUMBER/')(CoursePage)所做的是,它将CoursePage组件包装在HOC中,该HOC使得API请求获取与特定课程相关的数据,并且当它获得成功响应时{{1}使用作为props传递的数据呈现组件。同时显示加载屏幕。

现在,在CoursePage内,其内容的布局方式取决于用户是登录还是退出。

如果用户已注销,CoursePage组件将在LoggedOut的{​​{1}}方法内呈现,并且他们会看到一个页面,其中所有内容都会在页面中连续放置。< / p>

如果用户已登录,则CoursePage组件会在render()的{​​{1}}方法内呈现,并且他们会看到与上面相同的内容,但现在它已被分解为选项卡式部分,意味着用户无法再通过一次滚动查看页面的整个内容,他们必须选择相应的选项卡才能查看相关内容。

因此,例如,如果我已注销,并点击课程1的页面,我会转到LoggedIn,并依次查看包含3个部分(概述,内容,评论)的页面。

如果我已登录并点击课程1的页面,我会转到CoursePage并看到包含3个标签的页面(概述,内容,评论),然后点击每个标签应显示相关内容。< / p>

现在,我得到了以下要求:

当用户登录时,每个部分都应该在选择时反映URL。因此,如果我在登录时点击“内容”标签,则网址应为render()

问题

我决定使用ReactRouter实现此功能,因此,在www.page.com/courses/1组件的www.page.com/courses/1方法中,我创建了标签www.page.com/courses/1/contents元素,并放置了以下代码:

LoggedIn

render()只需将NavLink传递给相应的组件即可根据<Router> <section> <Route exact path="/courses/:courseName" render={(props) => { return this.determineVisibleSection('overview', data); }} /> <Route path="/courses/:courseName/:section" render={(props) => { return this.determineVisibleSection(props.match.params.section, data); }} /> </section> </Router> 进行渲染并返回。

问题在于,当单击某个部分时,整个页面会再次加载。

我的意思是,this.determineVisibleSection(sectionName, data)再次被触发,我们在等待数据返回时获得加载屏幕,最后页面显示我们单击的部分现在被选中以及下面的正确内容。

我想我明白为什么会这样。由于URL已更改,所有data组件都会收到更改通知,因此sectionName组件也会收到通知,因此,在基础fetch('courses/NUMBER/')(CoursePage)中,要呈现的组件每次都基本上是新的,甚至如果我们在同一页面上,由于Router返回了一个新页面,页面将被“重新加载”。

问题

有没有办法阻止这种行为?意思是,所选部分没有对URL进行更改会影响整个页面。它只会影响当前的课程页面内容。

我提出的一种方法似乎有效:

我像这样重写了我的基地Route

Router

fetch()()就是这个

Router

整个事情的关键是<Router> <Page> <Route exact path="/" component={HomePage} /> <Route path="/courses/:courseName" component={CoursePages} /> </Page> </Router> 以及我在CoursePages组件中有第二个class CoursePages extends React.Component { shouldComponentUpdate(nextProps, nextState) { return this.props.match.url !== nextProps.match.url; } render() { switch (this.props.match.url) { case '/courses/1': return React.createElement(fetch('courses/1/')(CoursePage), this.props, null); case '/courses/2': return React.createElement(fetch('courses/2/')(CoursePage), this.props, null); default: return <FourOFour />; } } } 的事实,因为第二个shouldComponentUpdate会强制其内容即使父组件没有重新渲染(因为<Router />

,也要重新渲染

有没有更好的方法可以解决这个问题?

1 个答案:

答案 0 :(得分:0)

我认为将部分路径放在LoggedIn组件中更好。因为它更像是react-router v4方式来处理这种情况(参见文档中的this basic example)。

首先,将基本路由器保持在第一个代码块中。根据给定的解释,我假设您的CoursePage组件或多或少是这样的。

class CoursePage extends Component{

  //...

  render(){
    return this.props.IsLoggedIn ? <LoggedIn/> : <LoggedOut/>
  }
}

现在将Routes放在LoggedIn组件中以用于不同的部分,如下所示。

import React, { Component } from 'react';
import {
  Switch
  Route,
  Redirect
} from 'react-router-dom'

class LoggedIn extends Component{

  // ...

  render(){
    const { match } = this.props;
    return (
      <Switch>
        {/* This will redirect /courses/:courseName to /courses/:courseName/overview */}
        <Redirect exact from={`${match.url}/`} to={`${match.url}/overview`}/>
        <Route path={`${match.url}/overview`} component={Overview}/>
        <Route path={`${match.url}/contents`} component={Contents}/>
        <Route path={`${match.url}/reviews`} component={Reviews}/>
      </Switch>
    );
  }
}

可能您需要向此渲染方法添加更多组件或HTML标记,以使其看起来像带标题的标签。

由于在CoursePage渲染后渲染剖面路径,因此当您导航到同一课程中的不同剖面时,它不会再次获取数据。