繁体   English   中英

TypeError:无法读取未定义(读取“过滤器”)和未定义错误的属性 - React

[英]TypeError: Cannot read properties of undefined (reading 'filter') and undefined error - React

提示:本站为国内最大中英文翻译问答网站,提供中英文对照查看,鼠标放在中文字句上可显示英文原文

我的 API 通话有问题。 我想为我的项目创建一个搜索栏,数据来自 API。 但是,当我添加过滤器 function 时出现错误。

TypeError: Cannot read properties of undefined (reading 'filter')

为了解决这个问题,我添加了可选的链接运算符,但它也不起作用,因为我得到“未定义”。 此外,为了获取值,我使用了 useEffect 钩子,但我不确定它是否是正确的解决方案。 我认为我的组件是在我的 API 调用未执行之前呈现的。 你能帮我修一下吗?

这是我的主要组成部分:

import "../App.css"
import APICall from "./APICall.js"
import Filter from "./Filter.js"
import {useState} from "react"

function App() {
  const [datum, setDatum] = useState([])
  
  return (
    <div className="App">
      <Filter datum={datum} />
      <APICall setDatum={setDatum} />
    </div>
  )
}

export default App

这是我进行 API 调用时的子组件:

import React from 'react'
import axios from "axios"
import { useState, useEffect } from 'react'

function APICall({setDatum}) {
  const [loading, setLoading] = useState(false)

  useEffect(() => {
    const fetchAPI = async () => {
      setLoading(true)
      try {
        const res = await axios(`https://api.spoonacular.com/food/products/search?query=yogurt&apiKey=`)
        setDatum(res.data.products)
        // console.log(datum)
      }
      catch(err) {
        console.log(err)
      }
      setLoading(false)
    }
    fetchAPI()
  }, [])

  if (loading === true) {
    return <div>Loading...</div>
  }
}

export default APICall

这是我遇到问题的另一个子组件:

import {useState, useEffect} from "react"

function Filter({datum}) {
  const [filterText, setFilterText] = useState("")

  const handleInput = (e) => {
    setFilterText(e.target.value)
  }

  useEffect(() => {
    const handleFilter = async () => {
      try {
         const filtered = await datum.title?.filter(item => {
          return Object.keys(item).some(key => 
           item[key].toString().toLowerCase().includes(filterText.toLocaleLowerCase())
          )
        })
        console.log(filtered)
      }
      catch (err) {
        console.log(err)
      }
    }
    handleFilter()
  }, [filterText])

  
  return (
    <div>
      <input type="text" placeholder="Please enter the name of the the food" onChange={handleInput} value={filterText} />

      {datum.map((el, id) => (
        <div key={id} className="items">
          <img src={el.image} alt={el.title} />
          <p>{el.title}</p>
        </div>
     ))}
    </div>
  )
}

export default Filter

编辑这是我从 API 获得的一些数据:

0: {id: 201369, title: 'Yoplait Yogurt, Lactose Free Yogurt, Peach, 6.0 oz', image: 'https://spoonacular.com/productImages/201369-312x231.jpeg', imageType: 'jpeg'}
1: {id: 415304, title: 'Noosa Key Lime Finest Yoghurt, 8 OZ', image: 'https://spoonacular.com/productImages/415304-312x231.jpeg', imageType: 'jpeg'}
2: {id: 89557, title: 'Yoplait Light Yogurt with Granola, Blueberry, Fat Free, 12 oz, 2 Cups', image: 'https://spoonacular.com/productImages/89557-312x231.png', imageType: 'png'}

我必须进行很多更改才能使其正常工作。 一些注意事项:你想按标题过滤,所以你做了datum.title.filter数据是一个数组,它没有标题属性,这就是你得到未定义的原因。 您必须使用datum.filter ,并且filter function 不是 promise,您不需要使用await 我还为过滤后创建了另一个state,并让原始数据保持不变,以便能够将itens重置为原始项目,否则如果您过滤了原始itens,它们会丢失。 我使Filter.js中的代码更简单,不需要useEffect,当你输入你改变filteredDatum的state和列表被过滤,我也是一个很好的搜索逻辑,搜索单独的词,例如,如果标题是“yougurt lactose 100”,如果搜索是“yog 100”,它会找到

应用程序.js

import "../App.css";
import APICall from "./APICall.jsx";
import Filter from "./Filter.jsx";
import { useState } from "react";

function App() {
  const [datum, setDatum] = useState([]);
  const [datumFiltered, setDatumFiltered] = useState([]);

  return (
    <div className="App">    
      <Filter datum={datum} datumFiltered={datumFiltered} setDatumFiltered={setDatumFiltered} />
      <APICall setDatum={setDatum} setDatumFiltered={setDatumFiltered} />
    </div>
  );
}

export default App;

过滤器.js

function Filter({ datum, datumFiltered, setDatumFiltered }) {
  const handleFilter = (e) => {
    const filterText = e.target.value.toLowerCase();
    const wordsToFilter = filterText.split(" ");
    datumFiltered = datum.filter((item) => {
      return wordsToFilter.every((word) => item.title.toLowerCase().includes(word));
    });
    setDatumFiltered(datumFiltered);
  };

  return (
    <div>
      <input type="text" placeholder="Please enter the name of the the food" onChange={handleFilter} />

      {datumFiltered.map((el, id) => (
        <div key={id} className="items">
          <img src={el.image} alt={el.title} />
          <p>{el.title}</p>
        </div>
      ))}
    </div>
  );
}

export default Filter;

APICall.js

import React from "react";
import axios from "axios";
import { useState, useEffect } from "react";

//REMOVE THIS FUNCTION
const axiosDummyCall = async () => {
  return [
    {
      id: 201369,
      title: "Yoplait Yogurt, Lactose Free Yogurt, Peach, 6.0 oz",
      image: "https://spoonacular.com/productImages/201369-312x231.jpeg",
      imageType: "jpeg",
    },
    {
      id: 415304,
      title: "Noosa Key Lime Finest Yoghurt, 8 OZ",
      image: "https://spoonacular.com/productImages/415304-312x231.jpeg",
      imageType: "jpeg",
    },
    {
      id: 89557,
      title: "Yoplait Light Yogurt with Granola, Blueberry, Fat Free, 12 oz, 2 Cups",
      image: "https://spoonacular.com/productImages/89557-312x231.png",
      imageType: "png",
    },
  ];
};

function APICall({ setDatum, setDatumFiltered }) {
  const [loading, setLoading] = useState(false);

  useEffect(() => {
    const fetchAPI = async () => {
      setLoading(true);
      try {
        let datum = await axiosDummyCall(); //REPLACE WITH REAL CALL
        setDatum(datum);
        setDatumFiltered(datum);
      } catch (err) {
        console.log(err);
      }
      setLoading(false);
    };
    fetchAPI();
  }, []);

  if (loading === true) {
    return <div>Loading...</div>;
  }
}

export default APICall;

关于第二个 state:

如果你只有一个 state,例如: ['yogurt', 'yogurt fat free', 'ketchup'] ,如果你输入yogurt ,则 state 会变成['yogurt', 'yogurt fat free'] , ketchup丢了。 如果您继续输入yogurt fat ,现在 state 再次更改为['yogurt fat free'] ,则丢失了 itens yogurtketchup 例如,您现在清除过滤器以再次显示所有项目,现在唯一出现的项目是yogurt fat free ,因为原来的 state 已更改,其他项目丢失。 您将不得不再次调用 API 再次填写列表。

这就是为什么我添加了第二个 state,这样整个列表就不会被触及,而且你总是可以再次找回所有的元素。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2023 STACKOOM.COM