在重新渲染之前,React Router显示带有旧组件/数据的动态路由

时间:2018-07-26 01:49:09

标签: reactjs react-router

编写我的第一个React应用程序。它有一个主页和艺术品的动态页面。我正在使用react-router,当我从首页> Art1>主页> Art2导航时,我发现行为异常。

在Art2页面上,页面将使用Art1中的数据进行渲染,然后组件将使用Art2中的正确数据进行重新渲染。

编辑:

App.js:

import "babel-polyfill"
import React, { Component } from "react"
import { BrowserRouter as Router, Route, Switch, Redirect } from "react-router-dom"

import Home from "./pages/home"
import PieceDetail from "./pages/pieceDetail"

class App extends Component {
  constructor(props) {
    super(props)
    this.state = {
      piece: {},
      locations: [],
      themes: [],
      types: [],
      piecesFilters: {
        search: ``,
        location: ``,
        theme: ``,
        type: ``
      },
      selectedMapPoint: ``,
      piecesLoading: true,
      pieces: [],
      homePageData: {},
      spotlightPiece: {},
      featuredPieces: [],
      homePageLoading: true,
      pieceDetails: {},
      pieceDetailsLoading: true
    }

    this.getHomePageData = this.getHomePageData.bind(this)
    this.getPieceDetails = this.getPieceDetails.bind(this)
    this.updatePiecesFilters = this.updatePiecesFilters.bind(this)
  }

  getHomePageData() {
    const api = `https://publicart.onecolumbiasc.com/w/wp-json/wp/v2`

    // Fetch home page data (home page settings - spotlight piece, featured posts and pieces)
    fetch(`${api}/pages/86`)
      .then(response => response.json())
      .then(json => {
        this.setState({ homePageData: json })

        // Fetch and set state for the spotlight piece details using the id from the above page fetch
        fetch(
          `${api}/pieces/${json.acf.spotlight_piece.ID}?_embed`
        )
          .then(response => response.json())
          .then(json => this.setState({ spotlightPiece: json }))

        // Get the ids for all featured pieces for a future fetch
        let featuredPiecesIds = json.acf.featured_pieces.map(piece => piece.feature_piece.ID)

        fetch(
          `${api}/pieces/?include[]=${featuredPiecesIds[0]}&include[]=${featuredPiecesIds[1]}&include[]=${featuredPiecesIds[2]}&_embed`
        )
          .then(response => response.json())
          .then(json => this.setState({ featuredPieces: json, loading: false }))
          .then(json => {
              return this.setState({
                homePageLoading: false
              })
            }
          )
      })
  }

  getPieceDetails(id) {
    fetch(
      `https://publicart.onecolumbiasc.com/w/wp-json/wp/v2/pieces/${id}?_embed`
    )
      .then(response => response.json())
      .then(json => this.setState(
        { 
          pieceDetails: json, 
          pieceDetailsLoading: false 
        }
      ))
      .catch(ex => console.log("parsing failed", ex))
  }

  updatePiecesFilters(filters) {
    this.setState({
      "piecesFilters": {
        ...filters
      }
    })

    if (this.state.piecesFilters.search !== filters.search) {
      this.setState({ "piecesLoading": true })
      this.getPiecesData(filters.search)
    }
  }

  componentDidMount() {
    // get themes
    fetch(
      `https://publicart.onecolumbiasc.com/w/wp-json/wp/v2/art_theme`
    )
    .then(response => response.json())
    .then(json => {
      return this.setState({ "themes": json })
    })
    .catch(ex => console.log("parsing failed", ex))

    // get types
      fetch(
        `https://publicart.onecolumbiasc.com/w/wp-json/wp/v2/art_type`
      )
      .then(response => response.json())
      .then(json => {
        return this.setState({ "types": json })
      })
      .catch(ex => console.log("parsing failed", ex))

  }

  render() {
    return (
      <Router>
        <div>
          <Switch>
            <Route 
              exact 
              path="/"
              render={
                props => 
                  <Home {...props}
                    homePageData={ this.state.homePageData }
                    spotlightPiece={ this.state.spotlightPiece }
                    featuredPieces={ this.state.featuredPieces }
                    loading={ this.state.homePageLoading }
                    getHomePageData={ this.getHomePageData } />
              }
            />
            <Route 
              path="/piece/:pieceid"
              render={
                props =>
                  <PieceDetail {...props}
                    piece={ this.state.pieceDetails }
                    loading={ this.state.pieceDetailsLoading } 
                    getPieceDetails={ this.getPieceDetails } 
                    update={ this.updatePiecesFilters } />
              } 
            />
          </Switch>
        </div>
      </Router>
    )
  }
}

export default App

PieceDetail组件:

/*eslint-disable no-unused-vars*/
import React, { Component, Fragment } from "react"
/*eslint-enable no-unused-vars*/
import "whatwg-fetch"
import styled, { ThemeProvider } from "styled-components"
import theme from "../Theme"

import Container from "../components/Container"
import Details from "../components/pieceDetail/Details"
import Footer from "../components/Footer"
import Gallery from "../components/pieceDetail/Gallery"
import Header from "../components/Header"
import HighlightBanner from "../components/pieceDetail/HighlightBanner"
import InfoSection from "../components/pieceDetail/InfoSection"
import Loader from "../components/Loader"
import Main from "../components/Main"
import Spotlight from "../components/Spotlight"

const VideoContainer = styled.div`
  margin: ${theme.margin.stackL};
`

const VideoHeading = styled.h1`
  font-size: ${theme.fontSizes.fontSize};
`
const Videos = styled.div``

const Video = styled.video`
  margin-top: ${theme.spaces.base};
  width: 100%;
`

class pieceDetail extends Component {

  componentDidMount() {
    const { pieceid } = this.props.match.params
    this.props.getPieceDetails(pieceid)
  }

  render() {

    return (
      <ThemeProvider theme={{ mode: "main" }}>
        <div className="App">
          {
            this.props.piece.acf ?
              <Spotlight
                image={ this.props.piece._embedded ?
                  this.props.piece._embedded["wp:featuredmedia"]["0"]
                    .media_details.sizes["piece-banner"].source_url
                  : null
                }
                overlay={{
                  heading: this.props.piece
                    ? this.props.piece.title.rendered
                    : null,
                    subheading: this.props.piece
                    ? this.props.piece.acf.artist
                    : null
                }}
              />
            : null
          }

          <Header />

          <div className="flex-grow">
            <Loader loading={ this.props.loading }>
              {
                this.props.piece.acf ?
                  <Fragment>
                    <InfoSection 
                      types={this.props.piece.acf.art_types}
                      year={this.props.piece.acf.year}
                      themes={this.props.piece.acf.art_themes}
                      address={this.props.piece.acf.address.address}
                      locationName={this.props.piece.acf.location_name}
                      locationNotes={this.props.piece.acf.location_notes}
                      buttonUrl={this.props.match.params.pieceid}
                      update={ this.props.update } />

                    <HighlightBanner 
                      show={this.props.piece.acf.collaboration_details.length > 0}
                      text={this.props.piece.acf.collaboration_details} />

                    <Main>
                      <Container>
                        <Details 
                          description={this.props.piece.acf.description}
                          articles={this.props.piece.acf.articles}
                        />
                        {
                          this.props.piece.acf.gallery ?
                            <Gallery
                              piece={this.props.piece}
                              gallery={this.props.piece.acf.gallery}
                              lightboxIsOpen={this.props.lightboxIsOpen}
                            />
                          : null
                        }
                        {
                          this.props.piece.acf.videos ?
                            <VideoContainer>
                              <VideoHeading>Videos</VideoHeading>
                              <Videos>
                                {
                                  this.props.piece.acf.videos.map(item =>
                                    <Video controls src={item.url} key={item.id}>Sorry, your browser doesn't support embedded videos</Video>
                                  )
                                }
                              </Videos>
                            </VideoContainer>
                          : null
                        }
                      </Container>
                    </Main>
                  </Fragment>
                : null
              }
            </Loader>
          </div>
          <Footer />
        </div>
      </ThemeProvider>
    )
  }
}

export default pieceDetail

1 个答案:

答案 0 :(得分:0)

在同事的帮助下,我们发现在加载艺术品的数据时,处于状态的loading属性未设置为true。我调整了App.js文件以重置该属性,然后将条件加载项添加到PieceDetails.js文件的Spotlight元素中,因为它不在<Loader>内。

代码更新

App.js:

getPieceDetails(id) {
    // UPDATE /////////////////////////////////////////////
    // set the loading back to true before fetch
    this.setState({pieceDetailsLoading: true})
    fetch(
      `https://publicart.onecolumbiasc.com/w/wp-json/wp/v2/pieces/${id}?_embed`
    )
      .then(response => response.json())
      .then(json => this.setState(
        { 
          pieceDetails: json, 
          pieceDetailsLoading: false 
        }
      ))
      .catch(ex => console.log("parsing failed", ex))
  }

PieceDetails.js:

render() {
    return (
      <ThemeProvider theme={{ mode: "main" }}>
          <div className="App">
            {
              // UPDATE /////////////////////////////////////////////
              // added a check for loading before showing this part
              this.props.piece.acf && !this.props.loading ?
                <Spotlight
                  image={ this.props.piece._embedded ?
                    this.props.piece._embedded["wp:featuredmedia"]["0"]
                      .media_details.sizes["piece-banner"].source_url
                    : null
                  }
                  overlay={{
                    heading: this.props.piece
                      ? this.props.piece.title.rendered
                      : null,
                      subheading: this.props.piece
                      ? this.props.piece.acf.artist
                      : null
                  }}
                />
              : null
            }