React Router показывает динамический маршрут со старым компонентом / данными перед повторной отрисовкой

Пишу свое первое приложение на React. У него есть домашняя страница и динамические страницы для произведений искусства. Я использую реагирующий маршрутизатор, и я заметил странное поведение, когда перехожу из Home> Art1> Home> 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.info("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.info("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.info("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

Пожалуйста, предоставьте мини-версию вашего кода, если нет, пожалуйста, включите код для вашего компонента PieceDetail

leogoesger 26.07.2018 03:58

Если вы предоставите дополнительный контекст, мы сможем вам помочь

Nickadiemus 26.07.2018 04:36

Добавлен контекст выше. Спасибо, что посмотрели - дайте мне знать, если мне нужно добавить дополнительную информацию.

Sara 26.07.2018 12:41
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Навигация по приложениям React: Исчерпывающее руководство по React Router
Навигация по приложениям React: Исчерпывающее руководство по React Router
React Router стала незаменимой библиотекой для создания одностраничных приложений с навигацией в React. В этой статье блога мы подробно рассмотрим...
Массив зависимостей в React
Массив зависимостей в React
Все о массиве Dependency и его связи с useEffect.
1
3
327
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

С помощью коллег мы выяснили, что свойство загрузки в состоянии не было возвращено к true при загрузке данных произведения искусства. Я скорректировал файл App.js, чтобы сбросить это свойство, а затем добавил условие загрузки в элемент прожектора файла PieceDetails.js, потому что его нет внутри <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.info("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
            }

Другие вопросы по теме