未捕获的TypeError:无法读取null的属性“ map”

时间:2019-08-30 00:42:28

标签: javascript reactjs react-router

我正在关注在线教程,直到我对路由器有所了解之前,一切都进行得很好。实际上,我删除了所有代码,并从github粘贴了教师的代码,但仍然收到此错误。文件夹结构和依赖项相同。我不知道当应用程序中断时如何解决此问题。命令行不显示此错误,仅显示浏览器

  

Recipes.js:7未捕获的TypeError:无法读取null的属性“地图”

import React, { Component } from 'react';
import './App.css';

import Form from "./components/Form";
import Recipes from "./components/Recipes";

const API_KEY = "xxxxxxxxxx";

class App extends Component {
    state = {
        recipes: []
    }
    getRecipe = async (e) => { 
        const recipeName = e.target.elements.recipeName.value;
        e.preventDefault();
        const api_call = await fetch(`https://cors-anywhere.herokuapp.com/http://food2fork.com/api/search?key=${API_KEY}&q=${recipeName}&count=10`);

        const data = await api_call.json();
        this.setState({ recipes: data.recipes });
        console.log(this.state.recipes);
    }
    componentDidMount = () => {
        const json = localStorage.getItem("recipes");
        const recipes = JSON.parse(json);
        this.setState({ recipes });
    }
    componentDidUpdate = () => {
        const recipes = JSON.stringify(this.state.recipes);
        localStorage.setItem("recipes", recipes);
    }
    render() {
        return (
            <div className="App">
                <header className="App-header">
                    <h1 className="App-title">Recipe Search</h1>
                </header>
                <Form getRecipe={this.getRecipe} />
                <Recipes recipes={this.state.recipes} />
            </div>
        );
      }
    }

export default App;}
{import React from 'react';

import { Link } from "react-router-dom";

const Recipes = props => (
    <div className="container">
        <div className="row">
        { props.recipes.map((recipe) => {
          return (
            <div key={recipe.title} className="col-md-4" style={{ marginBottom:"2rem" }}>
                <div className="recipes__box">
                  <img
                      className="recipe__box-img"
                      src={recipe.image_url}
                      alt={recipe.title}/>
                  <div className="recipe__text">
                      <h5 className="recipes__title">
                      { recipe.title.length < 20 ? `${recipe.title}` : `${recipe.title.substring(0, 25)}...` }
                      </h5>
                      <p className="recipes__subtitle">Publisher: <span>
                      { recipe.publisher }
                      </span></p>
                  </div>
                  <button className="recipe_buttons">
                      <Link to={{
                      pathname: `/recipe/${recipe.recipe_id}`,
                      state: { recipe: recipe.title }
                      }}>View Recipe</Link>
                  </button>
              </div>
          </div>
         );
       })}
    </div>
  </div>
);

export default Recipes;

5 个答案:

答案 0 :(得分:0)

您可以在代码中添加以下行,应用OR条件,当您第一次访问代码localStorage.getItem("recipes")的值为空时,因此,这表明您无法读取物业'map'为null'

 componentDidMount = () => {
        const json = localStorage.getItem("recipes") || [];
        const recipes = JSON.parse(json);
        this.setState({ recipes });
    }

答案 1 :(得分:0)

修复方法,可以在映射到数组之前添加真实性检查

props.recipes && props.recipes.map

在下面的修改后的代码中,由于其他答案所建议的新的空数组引用,因此不会导致重新渲染

componentDidMount = () => {
    const json = localStorage.getItem("recipes");
    const recipes = JSON.parse(json);
    recipes && this.setState({ recipes });
}

答案 2 :(得分:0)

要回答您的问题,我认为您需要在呈现方法中传递state而不是this.state

render() {
  return (
     <div className="App">
       <header className="App-header">
         <h1 className="App-title">Recipe Search</h1>
       </header>
       <Form getRecipe={this.getRecipe} />
       <Recipes recipes={state.recipes} />
     </div>
    );
  }
}

通常在类组件中使用状态时,在constructor中声明状态,因为它是在组件类中调用的第一个方法。 article进一步详细说明了在组件中的何处声明状态,但要旨是您的组件应如下所示:

class App extends Component {

  constructor() {
    this.state = {
      recipes: [],
    };
  }

  getRecipe = async (e) => { 
    const recipeName = e.target.elements.recipeName.value;
    e.preventDefault();
    const api_call = await fetch(`https://cors-anywhere.herokuapp.com/http://food2fork.com/api/search?key=${API_KEY}&q=${recipeName}&count=10`);

    const data = await api_call.json();
    this.setState({ recipes: data.recipes });
    console.log(this.state.recipes);
  }

  componentDidMount = () => {
    const json = localStorage.getItem("recipes");
    const recipes = JSON.parse(json);
    this.setState({ recipes });
  }

  componentDidUpdate = () => {
    const recipes = JSON.stringify(this.state.recipes);
    localStorage.setItem("recipes", recipes);
  }

  render() {
    return (
      <div className="App">
        <header className="App-header">
          <h1 className="App-title">Recipe Search</h1>
        </header>
        <Form getRecipe={this.getRecipe} />
        <Recipes recipes={this.state.recipes} />
      </div>
    );
  }
}

export default App;

答案 3 :(得分:0)

有几种方法可以解决此问题,我的解决方案是检查localStorage中的“ json”是否存在,即既不是null也不是undefined或为空字符串,...

componentDidMount = () => {
  const json = localStorage.getItem("recipes");

  if(json){
    const recipes = JSON.parse(json);
    this.setState({ recipes });
  }       
}

答案 4 :(得分:0)

我注释掉componentDidMount并在setState之前运行console.log(data),并收到一个带有{error:“ limit”}的对象。我检查了foodforfork api文档,并确定每天最多有50个免费请求。

明天我要检查一下是否恢复正常。我的下一个问题可能是发生这种情况时如何返回一条消息,而不仅仅是破坏应用程序。

谢谢大家!如果明天可行,我会标记为已回答

编辑:仅确认问题是由于API限制引起的。一切都按现在的方式进行。