开发者问题收集

我的反应代码正在运行,但是当我刷新页面时,我收到 TypeError: 无法读取未定义的属性“Location”

2020-05-31
2176

从 GamePage 开始,它提供了 2 个路由,分别呈现组件 GameList 和 GameDetailPage。两者最初都运行良好,但当我刷新 Gamelist 组件的页面时,它仍然会重新呈现该页面,但当我刷新 GameDetailPage 的页面时,我收到错误 TypeError:无法读取未定义的属性“Location”。我不明白为什么每次刷新时都无法从状态中获取数据。

gamepage.jsx

import React from "react";
import GamesList from "../../components/games-list/game-list.component";
import { Route } from "react-router-dom";
import GameDetailPage from "../gamedetailpage/gamedetailpage.component";
import {firestore,convertCollectionsSnapshotToMap} from '../../firebase/firebase.utils'
import {connect} from 'react-redux'
import {updateFootballGames} from '../../redux/games/games.actions'

class GamePage extends React.Component {

  unsubscribeFromSnapshot=null;

  //whenever the component mounts the state will be updated with the football games.
  componentDidMount(){
    const {updateFootballGames}=this.props
    const gameRef=firestore.collection('footballgames')
    gameRef.onSnapshot(async snapshot=>{
      const collectionsMap=convertCollectionsSnapshotToMap(snapshot)
      updateFootballGames(collectionsMap)
    })
  }
  render() {
    const { match } = this.props;
    return (
      <div className="game-page">
        <h1>games page</h1>
        <Route exact path={`${match.path}`} component={GamesList} />
        <Route path={`${match.path}/:linkUrl`} component={GameDetailPage}
         />
      </div>
    );
  }
}

const mapStateToProps=state=>({
  games:state.games.games
})

const mapDispatchToProps=dispatch=>({
  updateFootballGames:collectionsMap=>
  dispatch(updateFootballGames(collectionsMap))
})

export default connect(mapStateToProps, mapDispatchToProps)(GamePage);

gamedetailpage.component.jsx

  import React from "react";
    import { connect } from "react-redux";
    import GamePreview from '../../components/game-preview/game-preview.component'
    import GameDetails from '../../components/game-details/game-details.component'

const GameDetailPage = (props) => {
    const {games, match} = props
    const urlparam =match.params.linkUrl
    // const games_array = Object.entries(games)
    const gameObj=games[urlparam]
    console.log('prop',gameObj)


    return (
      <div className="game-list"> 
          <GameDetails game = {gameObj}/>
      </div>

    );

};




const mapStateToProps = (state) => ({
  games: state.games.games,
});

export default connect(mapStateToProps)(GameDetailPage);

game_details.component.jsx

import React from 'react';


const GameDetails = (props) => {
    console.log(props.game.Location)

    return(
    <div>
    Location:{props.game.Location}
    <br/>
    Price:{props.game.Price}
    </div>

    )
}

export default GameDetails;

gamelist.component.jsx

import React from "react";
import './game-list.styles.scss'
import GamePreview from "../game-preview/game-preview.component";
import {connect} from 'react-redux'

const GameList=(props)=>{
    const {games}=props
    console.log(games)
    const game_list=Object.entries(games)
    console.log(game_list)
    return (
      <div className="game-list">
        {game_list.map(game => 
                <GamePreview game = {game[1]}/>)}
      </div>

    );
  }

const mapStateToProps=state=>({
  games:state.games.games
})

export default connect(mapStateToProps)(GameList);

gamepreview.component.jsx

import React from "react";
import "./game-preview.styles.scss";
import { withRouter, Route } from "react-router-dom";


import GamePreviewDetail from "../game-preview-detail/game-preview-detail.component";

const GamePreview = (props) => {
  const { Location, Time, linkUrl, Price } = props.game;
  const { history, match } = props;
  return (
    <div
      className="game-preview"
      onClick={() => history.push(`${match.url}/${linkUrl}`)}
    >
      <div className="game-preview-image">
        <p>Picture goes here</p>
      </div>
      {/* <GamePreviewDetail name = {Location} price={Price}/> */}
      <p>Location:{Location}</p>
      <p>Price:{Price}</p>
    </div>
  );
};

export default withRouter(GamePreview);

app.js

import React from 'react';
import './App.css';
//import dependencies
import { Route, Switch } from "react-router-dom";
//import pages
import HomePage from './pages/homepage/homepage'
import GamesPage from './pages/gamespage/gamespage'
import SignInSignUp from './pages/signin-signup-page/signin-signup-page'

import GameDetailPage from "./pages/gamedetailpage/gamedetailpage.component";

import Header from './components/header/header.component';

import { auth, createUserProfileDocument } from './firebase/firebase.utils';

class App extends React.Component{
  constructor() {
    super();

    this.state = {
      currentUser: null
    } 
  }

  unsubscribeFromAuth = null

  componentDidMount() {
  this.unsubscribeFromAuth = auth.onAuthStateChanged(async userAuth => {
    if (userAuth) {
      const userRef = await createUserProfileDocument(userAuth);
      // check if the snapshot has changed (subscribe)
      // get the user that we just created or that already exists in the db
      userRef.onSnapshot(snapshot => {
        this.setState({
          currentUser: {
            id: snapshot.id,
            ...snapshot.data()}
        })
      })  
    } else {
      this.setState({currentUser: userAuth})
    }

    })
  }

  componentWillUnmount() {
    this.unsubscribeFromAuth();
  }

  render(){
    return(
      <div>
        <Header currentUser = {this.state.currentUser}/>
         <Switch>
          <Route exact path="/" component={HomePage} />  
          <Route path="/games" component={GamesPage} />  
          <Route exact path="/signin" component={SignInSignUp} />  
        </Switch>
      </div>
    )
  }
}
export default App;
1个回答

我会尝试使用 useParams 钩子。然后使用 useEffect 钩子捕获 linkUrl 的任何更改。还通过 useState 引入了 gameObj

useParams returns an object of key/value pairs of URL parameters. Use it to access match.params of the current <Route> .

If you're familiar with React class lifecycle methods, you can think of useEffect Hook as componentDidMount , componentDidUpdate , and componentWillUnmount combined.

尝试修改 <GameDetailPage /> 组件,如下所示:

import React, { useState, useEffect } from 'react';
import { useParams } from "react-router-dom";
// other imports

const GameDetailPage = (props) => {
   const { games } = props;
   let { linkUrl } = useParams();
   const [ gameObj, setGameObj ] = useState(null);

   useEffect(() => {
      if (games) {
         const newGameObj = games[linkUrl];
         console.log('game object', newGameObj);

         setGameObj(newGameObj);
      }
   }, [games, linkUrl]);

   return <div className="game-list"> 
      { gameObj && <GameDetails game={ gameObj } /> }
   </div>
}

+1 - null 检查:

您还可以在 gameObj 的返回语句中看到 null 检查,一旦在 games 数组中找到 linkUrl 值,它就会帮助仅渲染该情况。

希望这对您有所帮助!

norbitrial
2020-05-31