React路由器没有第二次点击呈现

时间:2018-11-19 14:06:38

标签: reactjs

我使用Router像下面的代码那样在组件之间切换,包括Home,Sidebar,Detail,Category。

对于第一次加载,它将显示所有最近的帖子,特色帖子。 当我单击某个帖子以查看详细信息时,效果很好。 在详细信息页面中,我单击以渲染新帖子,但不渲染。

我的代码:

null

请查看照片:

enter image description here

我的详细信息:

class App extends React.Component {
    render () {
        // if ('serviceWorker' in navigator) {
        //     const registration = runtime.register();
        // }
        module.hot.accept(); 
        $("body").removeClass();
        $("body").addClass("homepage");
        <Helmet>
            <title>{blog_title}</title>
            <meta name="description" content={blog_description} />
        </Helmet>
        const {feature, main, sidebar, mainbottom, header } = this.props;
        return (
            <div id="all">
                {header}
                <div className="container">
                    <div className="main-feature" id="main-feature">
                        {feature}
                    </div>
                </div>
                <div id="content" className="site-content">
                    <div className="container">
                        <div className="divcontainer">
                            <div id="po-homepage" className="content-area">
                                {main}
                            </div>
                            <aside id="secondary" className="sidebar widget-area">
                                <div className="popular_post" id="popular_post">
                                    {sidebar}
                                </div>
                            </aside>
                        </div>
                    </div>
                </div>
                <div className="cat-list">
                    <div className="container">
                        <div className="thecategories" id="thecategories">
                            {mainbottom}
                        </div>
                    </div>
                </div>
            </div>
        )
    }
}

当我添加ComponentDidUpdate()时,它可以工作,但是在渲染新帖子之前先渲染回环顶部的细节。我这样使用。

import React, {Component} from "react"; //nếu chỉ import React thì sẽ cần React.Component
import $ from 'jquery';
import { Helmet } from "react-helmet";
import {
  BrowserRouter as Router,
  Route,
  Switch
} from 'react-router-dom';

class Detail extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      post: {}
    };
  }

  componentDidMount() {

    //scroll to detail
    $(document).ready(function(){
      $("html, body").animate({ scrollTop: $("#content").offset().top - 100 }, 500);
      $("body").removeClass();
      $("body").addClass("detailpage");
    }); 

    console.log(this.props.detailink); 

    var that = this; 
    var url = window.location.href.split("/");
    var slug = url.pop() || url.pop();
   // console.log(CelestialSettings.URL.api + "/posts?slug=" + slug);
    fetch(CelestialSettings.URL.api + "/posts?slug=" + slug)
      .then(function(response) {
        if (!response.ok) {
          throw Error(response.statusText);
        }
        return response.json();  
      })
      .then(function(res) {
        that.setState({ post: res[0] });
      });
  }

  renderPosts() {
    return (
      <div className="card">
        <div className="card-body">
          <Helmet>
            <title>{this.state.post.title.rendered}</title>
            <meta name="description" content={this.state.post.excerpt.rendered.replace(/<\/?[^>]+(>|$)/g, "")} />
          </Helmet>
          <h1 className="card-title">{this.state.post.title.rendered}</h1>
          <p className="card-text">
            <small className="text-muted">
              {this.state.post.author_name} &ndash;{" "}  
              {this.state.post.published_date}
            </small>
          </p>
          {this.state.post.featured_image_src ? (
            <img
              className="featured-image"
              src={this.state.post.featured_image_src}
              alt="featured image"
            />
          ) : null}
          <p
            className="card-text"
            dangerouslySetInnerHTML={{
              __html: this.state.post.content.rendered
            }}
          />
        </div>
      </div>
    );
  }

  renderEmpty() {
    return (
     <div></div>
    );
  }

  render() {
    var href = window.location.href+"/?view=react"; 
    return (
      <div className="container post-entry">
        {this.state.post.title ? this.renderPosts() : this.renderEmpty()}
      </div>
    );
  }
}

export default Detail;

对我的问题有任何建议吗?非常感谢。

1 个答案:

答案 0 :(得分:2)

您的Detail组件需要知道url发生了更改,并且由于在尝试呈现时未传递任何相关属性,因此您必须使用react路由器提供的withRouter HOC

因此在“详细信息”组件文件的顶部

import {
  BrowserRouter as Router,
  Route,
  Switch,
  withRouter // add this (and the comma in the above line)
} from 'react-router-dom';

export使用的底部

export default withRouter(Detail);

更新

多读一些Details代码,我发现您fetch生命周期事件中的内容ComponentDidMount,但是当您加载新帖子时,您将停留在同一页面上,因此Details组件未卸载/重新安装,只是使用新的道具进行了更新,因此ComponentDidMount不会再次触发。您还必须使用ComponentDidUpdate

一些其他信息

  1. 由于您正在使用react-router,因此您不应该自己解析window.location.href来试图解决这一问题。您可以自动将其从路由器提供的道具中传下来。

    <!-- language: lang-js -->
    
    <Route
      path={CelestialSettings.path + 'posts/:slug'} 
      render={(props) => <App header={<Header/>} 
                          main={<Detail slug={props.match.slug} detailink={CelestialSettings.path + 'posts/:slug'} />} 
                          sidebar={<Popular />} 
                          feature={<Featurex/>} 
                          mainbottom={<Categories/>} />} />
    
  2. 然后在您的ComponentDidUpdate

    <!-- language: lang-js -->
    
    componentDidUpdate(newProps) {
      const {slug} = newProps;
      const that = this; // you do not need this if you use arrow functions
    
      if (slug !== this.props.slug) {
        fetch(CelestialSettings.URL.api + "/posts?slug=" + slug)
          .then(function(response) {
            if (!response.ok) {
              throw Error(response.statusText);
            }
            return response.json();
          })
          .then(function(res) {
            that.setState({
              post: res[0]
            });
          });
      }
    }