React router 4 `Link` 组件仅更改 url 而不更新路由

React router 4 `Link` component only changing the url and not updating the route

我在使用 react-router-dom Link 组件时遇到问题,仅更改 URL 而未更新路由。

来自 /courses -> /courses/<course-slug>
的链接工作正常 然后 /courses/<course-slug> -> /lessons/<lesson-slug>

然而,我在链接到其他课程时遇到问题,例如来自 /lessons/<lesson-slug> -> /lessons/<different-lesson-slug>

它似乎只更新 LessonsList 组件并更新 URL 但不更新路由/内容或父级 Lesson.

我已经确保将匹配、位置属性传递给组件,以防它与更新阻止有关 - https://reacttraining.com/react-router/web/guides/dealing-with-update-blocking 但它似乎仍然不起作用。

看不出哪里错了,应该比较简单

这与我设置路线的方式或具有相同路线的路线有任何关系吗?

这是我的依赖项和代码,任何正确方向的观点都会受到赞赏。

"dependencies": {
    "axios": "^0.16.2",
    "prop-types": "^15.5.10",
    "react": "^15.6.1",
    "react-dom": "^15.6.1",
    "react-router-dom": "^4.1.2"
 }

index.js

    import css from '../css/index.scss';
    import React from 'react';
    import ReactDOM from 'react-dom';
    import { BrowserRouter as Router } from 'react-router-dom';
    import App from './components/App';

    ReactDOM.render(
      <Router>
        <App />
      </Router>
    , document.getElementById('app'));

App/index.js

import React, { Component } from 'react';
import Header from '../Header';
import Main from '../Main';
import Footer from '../Footer';

class App extends Component {
  render() {
    return(
      <div>
        <Header />
        <Main />
        <Footer />
      </div>
    );
  }
}

export default App;

Main/index.js

import React, { Component } from 'react';
import { Route, Link, Switch } from 'react-router-dom';
import Home from '../Home';
import Courses from '../Courses';
import Course from '../Course';
import Lessons from '../Lessons';
import Lesson from '../Lesson';

class Main extends Component {
  constructor(props) {
    super(props);
  }

  render() {
    return(
      <div className="main">
        <Switch>
          <Route exact path="/" component={Home}/>
          <Route path="/courses/:course" component={Course}/>
          <Route exact path="/courses" component={Courses}/>
          <Route path="/lessons/:lesson" component={Lesson}/>
          <Route exact path="/lessons" component={Lessons}/>
          <Route render={ () => (
            <div>Not Found 404</div>
          )}/>
        </Switch>
      </div>
    );
  }
}

export default Main;

Lessons/index.js

import React, { Component } from 'react';
import api from '../../utils/api';
import LessonsList from '../LessonsList';
import { Link } from 'react-router-dom';

class Lessons extends Component {
  constructor(props) {
    super(props);

    this.state = {
      lessons: null
    };
  }

  componentDidMount() {
    api.getAllLessons()
      .then((lessons) => {
        this.setState({
          lessons: lessons
        });
      });
  }

  render() {
    return(
      <div className="lessons">
        {!this.state.lessons ?
          <div>Loading...</div>
          :
          <div>
            <LessonsList 
              lessons={this.state.lessons}
              {...this.props}
            />
          </div>
        }
      </div>
    );
  }
}

export default Lessons;

Lesson/index.js

import React, { Component } from 'react';
import api from '../../utils/api';
import LessonsList from '../LessonsList';
import { Link } from 'react-router-dom';

class Lesson extends Component {
  constructor(props) {
    super(props);

    this.state = {
      lesson: null
    }
  }

  componentDidMount() {
    api.getLesson(this.props.match.params.lesson)
      .then((lesson) => {
        this.setState({
          lesson: lesson[0]
        });
      });
  }

  render() {
    return(
      <div className="lesson">
        {!this.state.lesson ?
          <div>Loading...</div>
          :
          <div>
            <h3>Course title: {this.state.lesson.course.title}</h3>
            <h1>Lesson: {this.state.lesson.title}</h1>
            <h2>Other lessons from this course</h2>
            <LessonsList
              lessons={this.state.lesson.lessons}
              {...this.props}
            />
          </div>
        }
      </div>
    );
  }
}

export default Lesson;

LessonsList/index.js

import React, { Component } from 'react';
import PropTypes from 'prop-types';
import { Link } from 'react-router-dom';

function LessonsList(props) {
  return(
    <ul>
      {props.lessons.map((lesson) => {
        return(
          <li key={lesson.id}>         
            <Link to={`/lessons/${lesson.slug}`}>{lesson.title}</Link>
          </li>
        );
      })}
    </ul>
  );
}

LessonsList.propTypes = {
  lessons: PropTypes.array.isRequired
}

export default LessonsList;

更新:

这是更新后的组件 componentWillReceiveProps

Lesson/index.js

import React, { Component } from 'react';
import api from '../../utils/api';
import LessonsList from '../LessonsList';
import { Link } from 'react-router-dom';

class Lesson extends Component {
  constructor(props) {
    super(props);

    this.state = {
      lesson: null
    }
  }

  componentDidMount() {
    api.getLesson(this.props.match.params.lesson)
      .then((lesson) => {
        this.setState({
          lesson: lesson[0]
        });
      });
  }

  componentWillReceiveProps(nextProps) {
    if(this.props.match.params.lesson !== nextProps.match.params.lesson) {
      api.getLesson(nextProps.match.params.lesson)
        .then((lesson) => {
            this.setState({
            lesson: lesson[0]
          });
        });
    }
  }

  render() {
    return(
      <div className="lesson">
        {!this.state.lesson ?
          <div>Loading...</div>
          :
          <div>
            <h3>Course title: {this.state.lesson.course.title}</h3>
            <h1>Lesson: {this.state.lesson.title}</h1>
            <h2>Other lessons from this course</h2>
            <LessonsList
              lessons={this.state.lesson.lessons}
              {...this.props}
            />
          </div>
        }
      </div>
    );
  }
}

export default Lesson;

此问题与 componentDidMount 事件有关。当你改变课程时它不会被解雇。所以你应该使用componentDidUpdate来改一课。

  componentDidUpdate() {
    if (this.props.match.params.lesson !== this.state.lesson.slug)
     api.getLesson(this.props.match.params.lesson)
          .then((lesson) => {
            this.setState({
              lesson: lesson[0]
            });
          });
        }
      }

您的 <Lesson /> 组件仅在 componentDidMount 生命周期挂钩期间设置课程。如果您在上课时更换了 slug,它不会导致组件重新安装。您可以使用 componentWillReceiveProps 生命周期挂钩来完成您想要的。

componentWillReceiveProps(nextProps) {
    api.getLesson(nextProps.match.params.lesson)
        .then((lesson) => {
            this.setState({
            lesson: lesson[0]
        });
    });
}