我的反应代码正在运行,但是当我刷新页面时,我收到 TypeError: 无法读取未定义的属性“Location”
从 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;
我会尝试使用
useParams
钩子。然后使用
useEffect
钩子捕获
linkUrl
的任何更改。还通过
useState
引入了
gameObj
。
useParams
returns an object of key/value pairs of URL parameters. Use it to accessmatch.params
of the current<Route>
.If you're familiar with React class lifecycle methods, you can think of
useEffect
Hook ascomponentDidMount
,componentDidUpdate
, andcomponentWillUnmount
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
值,它就会帮助仅渲染该情况。
希望这对您有所帮助!