【问题标题】: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 可能是 undefinedrecipes 仍然是一个空数组 [])。类似currentRecipe ? &lt;h1&gt;{currentRecipe.recipe.label}&lt;/h1&gt; : &lt;h1&gt;Recipe not found&lt;/h1&gt;
  • @Jackyef 它现在正在工作,首先它说没有找到食谱,但 1 秒后它会显示食谱。你能告诉这是怎么回事吗?这是让它工作的唯一方法吗?

标签: javascript reactjs api react-router


【解决方案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...";
}

【讨论】:

    猜你喜欢
    • 2018-05-10
    • 2017-09-23
    • 2022-01-21
    • 1970-01-01
    • 2017-11-01
    • 1970-01-01
    • 2021-12-19
    • 2022-12-16
    • 2020-05-22
    相关资源
    最近更新 更多