React Child componentDidMount不在Route上触发

时间:2018-03-02 04:20:11

标签: javascript reactjs react-router react-router-v4

我是React的新手,并且一直在寻找用无头WP后端构建我的第一个反应应用程序。

我无法在componentDidMount课程中触发MoviePage。我希望有人能帮助我理解我做错了什么。

这是我的代码,它可能并不完美,因为这是我第一次尝试。

注意代码现已改变以添加评论的建议 - 检查原始代码的编辑历史记录(它仍然已损坏)

index.js

import React from 'react';
import ReactDOM from 'react-dom';
import { BrowserRouter } from 'react-router-dom';
import './index.css';
import App from './App';
import registerServiceWorker from './registerServiceWorker';

ReactDOM.render((
        <BrowserRouter>
            <App />
        </BrowserRouter>
    ), 
    document.getElementById('root'));
registerServiceWorker();

App.js

import React from 'react';

import Header from './components/Header';
import Main from './components/Main';

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

export default App;

Header.js

import React from 'react';
import { Link } from "react-router-dom";

class Header extends React.Component {
  constructor() {
    super();
    this.state = {
      movies: []
    }
  }

  componentDidMount() {
    let dataURL = "http://localhost:8888/SBP/website/wp-json/wp/v2/movies?_embed";

    fetch(dataURL)
      .then(response => response.json())
      .then(response => {
        this.setState({
          movies: response
        })
      })
  }

  render() {
    let movieLinks = this.state.movies.map((movie, index) => {
      return <li key={index}><Link to={'/movies/'+movie.id}>{movie.title.rendered}</Link></li>
    });

    return (
      <header>
        <nav>
          <ul>
            <li><Link to='/movies'>All Movies</Link></li>
            {movieLinks}
          </ul>
        </nav>
      </header>
    )
  }  
}

export default Header;

Main.js

import React from 'react';
import { Route } from "react-router-dom";

import Movies from './Movies';

class Main extends React.Component {
  render() {
    return (
      <main>
        <Route path='/movies' component={Movies}/>
      </main>
    )
  }
}

export default Main;

Movies.js

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

import MoviesHub from './MoviesHub';
import MoviePage from './MoviePage';

class Movies extends React.Component {
  render() {
    return (
      <Switch>
        <Route exact path='/movies' component={MoviesHub}/>
        <Route path='/movies/:number' component={MoviePage}/>
      </Switch>
    )
  }
}

export default Movies;

MoviesHub.js

import React from 'react';

class MoviesHub extends React.Component {
  constructor() {
    super();
    this.state = {
      movies: []
    }
  }

  componentDidMount() {
    let dataURL = "http://localhost:8888/SBP/website/wp-json/wp/v2/movies?_embed";
    fetch(dataURL)
      .then(res => res.json())
      .then(res => {
        this.setState({
          movies: res
        })
      })
  }

  render() {
    let movies = this.state.movies.map((movie, index) => {
      return <div key={index}>
      <img src={movie._embedded['wp:featuredmedia'][0].media_details.sizes.large.source_url} alt={movie.title.rendered} />
      <p><strong>Title:</strong> {movie.title.rendered}</p>
      <p><strong>Release Year:</strong> {movie.acf.release_year}</p>
      <p><strong>Rating:</strong> {movie.acf.rating}</p>
      <div><strong>Description:</strong><div dangerouslySetInnerHTML={ {__html: movie.acf.description} } /></div>
      </div>
    });

    return (
      <div>
        <h2>Star Wars Movies</h2>
        {movies}
      </div>
    )
  }
}

export default MoviesHub;

MoviePage.js

import React from 'react';

class MoviePage extends React.Component {
  constructor() {
    super();
    this.state = {
      movie: []
    }
  }

  componentDidMount() {
    console.log('MoviePage componentDidMount');

    let dataURL = 'http://localhost:8888/SBP/website/wp-json/wp/v2/movies/'+this.props.match.params.number;

    fetch(dataURL)
      .then(results => {
        return results.json();
      })
      .then(data => {
        debugger;

        this.setState({
          movie: data
        })

        console.log("movie", this.state.movie);
      })
  }

  render() {
    let movie = this.state.movie;

    return <div>
        <img src={movie._embedded['wp:featuredmedia'][0].media_details.sizes.large.source_url} alt={movie.title.rendered} />
        <p><strong>Title:</strong> {movie.title.rendered}</p>
        <p><strong>Release Year:</strong> {movie.acf.release_year}</p>
        <p><strong>Rating:</strong> {movie.acf.rating}</p>
        <div><strong>Description:</strong><div dangerouslySetInnerHTML={ {__html: movie.acf.description} } /></div>
      </div>
  }
}

export default MoviePage;

作为参考我将从this tutorial构建并尝试将其提升到新的水平

我们将非常感谢任何帮助,并且对如何改进我的代码以保持与最佳实践保持一致的任何建议都会很棒。

谢谢大家。

1 个答案:

答案 0 :(得分:1)

我认为问题在于您实际上并未将您的反应应用程序附加到DOM。在某个地方,您需要使用ReactDOM将您的应用程序附加到页面上的某个根元素。然后,您的组件将安装并呈现。

对你来说,这可能看起来像这样:

ReactDOM.render(App, document.getElementById('my-root-element'))

请查看the documentation了解详情。

修改

我认为您可能会因渲染错误而导致此错误。如果在初始渲染时出现错误,则永远不会将其发送到componentDidMount。

如果查看MoviePage类,则在初始化时设置movie: []状态。你最终会获取一部电影,这可能是一个对象。但是在你完成获取数据之前,你将调用你的渲染函数,它试图访问该电影的数据,如:

movie._embedded['wp:featuredmedia'][0].media_details.sizes.large.source_url

两个快速提示:

  1. 使用与您希望州返回的类型相同的类型预填充您的州。因此,如果您希望电影成为对象,则初始状态为movie: {}
  2. 在使用数据渲染元素之前,请确保已加载数据。有一个条件,您可以在其中呈现微调器或加载消息,直到数据返回。
  3. 渲染函数示例:

    render() {
      if (Object.keys(movie).length === 0) { // check if movie object is empty
        return <div>Data not loaded</div>;
      } else {
        return (
          ... whatever you had
        );
      }
    }