无法在页面刷新时读取未定义反应路由器的属性
Posted
技术标签:
【中文标题】无法在页面刷新时读取未定义反应路由器的属性【英文标题】:Cannot read properties of undefined react router on page refresh 【发布时间】:2021-12-31 07:19:57 【问题描述】:我正在使用 Edamam 食谱 API 制作食谱应用程序。在我刷新食谱详细信息页面之前,一切正常。当我打开食谱时它工作正常,但是当我刷新页面时,例如 http://localhost:3000/recipe/Pasta%20alla%20Gricia%20Recipe
它给了我一个错误:
Cannot read properties of undefined (reading 'recipe')
我不知道为什么会发生这种情况。当页面没有刷新时它正在工作。
App.js:
import React from "react";
import Home from "./pages/Home";
import ShowRecipe from "./pages/ShowRecipe";
import RecipeDetail from "./pages/RecipeDetail.js";
import
Routes,
Route,
Link
from "react-router-dom";
function App()
return(
<div>
<ul>
<li><Link to="/">Home</Link></li>
<li><Link to="/recipe">Recipe</Link></li>
</ul>
<Routes>
<Route path="/" element=<Home /> />
<Route path="/recipe" element=<ShowRecipe /> />
<Route path="/recipe/:recipeId" element=<RecipeDetail /> />
</Routes>
</div>
)
export default App;
ShowRecipe.js:
import React,useContext,useState,useEffect from "react";
import Link from "react-router-dom";
import Context from "../Context"
function ShowRecipe()
const recipes,getSearch,search,handleChange = useContext(Context)
let dispRecipe = recipes.map(recipe => (
<div>
<img src=recipe.recipe.image />
<Link to=`/recipe/$recipe.recipe.label`><h1>recipe.recipe.label</h1></Link>
<p>recipe.recipe.calories</p>
</div>
))
return(
<div>
<form onSubmit=getSearch>
<input type="text" value=search onChange=handleChange/>
<button type="submit">Search</button>
</form>
dispRecipe
</div>
)
export default ShowRecipe;
RecipeDetail.js:
import React,useContext from 'react';
import useParams from "react-router-dom"
import Context from "../Context"
function RecipeDetail()
const recipes = useContext(Context)
const recipeId = useParams()
const currentRecipe = recipes.find(recipe => recipe.recipe.label === recipeId)
return(
<div>
<h1>currentRecipe.recipe.label</h1>
</div>
)
export default RecipeDetail
Context.js:
import React, useState, useEffect from "react"
const Context = React.createContext()
function ContextProvider(children)
const API_KEY = "648ac4cc09c9168758cc92c64b18ecfc"
const API_ID = "854d3ad3"
const [recipes , setRecipes] = useState([])
const [search, setSearch] = useState("")
const [query, setQuery] = useState("pasta")
let example =`https://api.edamam.com/search?q=$query&from=0&to=20&app_id=$API_ID&app_key=$API_KEY`
useEffect(()=>
fetch(example)
.then(res => res.json())
.then(data =>
setRecipes(data.hits);
console.log(data)
)
, [query])
const handleChange = (e) =>
setSearch(e.target.value)
console.log(search)
const getSearch = (e) =>
e.preventDefault()
setQuery(search)
console.log(recipes)
return (
<Context.Provider value=
recipes,
search,
getSearch,
handleChange,
>
children
</Context.Provider>
)
export ContextProvider, Context
【问题讨论】:
我认为您需要检查currentRecipe
是否在RecipeDetail
中定义。当应用程序最初启动时,currentRecipe
可能是 undefined
(recipes
仍然是一个空数组 []
)。类似currentRecipe ? <h1>currentRecipe.recipe.label</h1> : <h1>Recipe not found</h1>
@Jackyef 它现在正在工作,首先它说没有找到食谱,但 1 秒后它会显示食谱。你能告诉这是怎么回事吗?这是让它工作的唯一方法吗?
【参考方案1】:
在这一行中,您正在为您的 React 应用程序创建上下文
const Context = React.createContext()
createContext
调用的参数是初始状态——这里它是未定义的。因为没有初始状态,所以这个上下文的值是未定义的。
这不是很直观,但这个初始值是您应用程序中的组件在第一次渲染期间将收到的值——即使您在提供程序中设置了value
。
console.log(useContext(Context)) // undefined
您稍后尝试解构这个未定义的对象
const recipes,getSearch,search,handleChange = useContext(Context)
这会导致错误“无法读取未定义的属性”。
当您使用 react 的路由移动到页面时,上下文已经有足够的时间使用您期望的值进行初始化。当您刷新页面时,上下文没有足够的时间使用您期望的值进行初始化。因此,您最终会看到此错误。
正如一位助手已经说过的,您应该在尝试访问之前检查上下文中的值是否可用。您有多种选择。
等待定义上下文值
const context = useContext(Context)
if (!context)
return "Loading..."
在上下文中设置初始值
const Context = React.createContext(
recipes: []
)
在您的上下文中建模加载状态
const Context = React.createContext(
recipes: null,
isLoading: true,
)
// ...
const [isLoadingRecipes , setLoadingRecipes] = useState(true)
// ...
useEffect(()=>
setLoadingRecipes(true)
fetch(example)
.then(res => res.json())
.then(data =>
setRecipes(data.hits);
setLoadingRecipes(false);
console.log(data)
)
, [query])
// ...
const recipes, isLoading = useContext(Context)
if (!recipes && isLoading)
return "Loading...";
【讨论】:
以上是关于无法在页面刷新时读取未定义反应路由器的属性的主要内容,如果未能解决你的问题,请参考以下文章
Apollo 查询在页面刷新时运行,但不使用反应路由器导航?