React Child componentDidMount不在Route上触发

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了React Child componentDidMount不在Route上触发相关的知识,希望对你有一定的参考价值。

我是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建设,并试图将其提升到一个新的水平

任何帮助将不胜感激,并且任何关于如何改进我的代码以符合最佳实践的建议都会很棒。

谢谢大家。

答案

我认为问题在于你实际上并没有将你的反应应用程序附加到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. 在使用数据呈现元素之前,请确保已加载数据。有一个条件,您可以在其中呈现微调器或加载消息,直到数据返回。

示例渲染功能:

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

以上是关于React Child componentDidMount不在Route上触发的主要内容,如果未能解决你的问题,请参考以下文章

React 组件间通讯

React Context - Context和Child render没有更新。

对象作为 React-Child 无效 > 使用数组代替异常

react native routerflux 遇到两个key相同的child

来自一个函数的 React Child 错误正在引用另一个函数

React Child componentDidMount不在Route上触发