Filter response from api on user search getting error :`Unhandled Rejection (TypeError): Cannot read property 'results' of undefined`

Filter response from api on user search getting error :`Unhandled Rejection (TypeError): Cannot read property 'results' of undefined`

正在尝试使用过滤后的 api 响应更新我的状态。我拨打电话,然后更新 results 状态(见下文)。

api 通话

  async searchMovies(keyword, year) {
    const response = await getMoviesFiltered(keyword, year);
    console.log(response); // filtered response
    this.setState({ results: response.results});
  }

请求

export const getMoviesFiltered = async (keyword, year) => {
  try {
    const response = await axios.get(
      `https://api.themoviedb.org/3/search/movie?api_key=<apikey>&language=en-US&query=${keyword}&page=1&include_adult=false&year=${year}`
    );
    console.log(response.data.results);
    return response.data;

  } catch (error) {
    console.error(error);
  }
};

来自api的回复:

{page: 1, results: Array(20), total_pages: 95, total_results: 1889}
page: 1
results: (20) [{…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}, {…}]
total_pages: 95
total_results: 1889

我想用响应(结果键,它是一个数组)更新我的状态并映射它,但它告诉我 Unhandled Rejection (TypeError): Cannot read property 'results' of undefined 这很奇怪,因为我可以在响应

中看到 results

此外,当我尝试更新 response 状态下的结果时,例如

this.setState({ results: response});

我得到:

TypeError: movies.map is not a function

即它无法映射我传递的响应.... 我查看了堆栈上的其他问题,他们说这是因为响应不是数组,但我的是 :S

这里是我映射数据的地方,它是从父级传递下来的。

 <MovieList movies={results || []} genres={genreOptions || []} />

组件:

    return (
      <MoviesWrapper>
        {movies && movies.map((movie, index) => {
          const {
            title,
            vote_average,
            overview,
            release_date,
            poster_path,
            genre_ids,
          } = movie;
          return (
            <MovieItem
              key={index}
              title={title}
              rating={vote_average}
              overview={overview}
              release={release_date}
              poster={poster_path}
              movieGenres={matchGenres(genre_ids)}
            />
          );
        })}

谁能看出哪里出了问题?

看不到你的完整组件代码;但问题可能是您将状态初始化为 null。

当您在代码中定义状态时,状态会使用其初始值进行初始化。

const [Movies, setMovies] = useState(null)

现在我已经定义了一个名为 Movies 的状态,它的开头为 null。

我在 useEffect 块(或 ComponentDidMount)进行 API 调用;在我的 API 响应之后,我将状态更新为使用 setState 响应,或者在上面的示例中; setMovies().

useEffect(() => {
   const response = await axios.get(`ENDPOINT_URL`);
   setMovies(response) 
},[]);

现在我的状态是来自 API 调用的响应数组。只有现在我可以使用地图功能,以前不能;因为它为 null 并且会引发错误。

让我们深入探讨 React 如何在 return 块中处理此流程。 React 不会等待 API 调用结束来初始化状态并打印 return 块中的内容。这个很重要;因为如果我尝试在第一次渲染时对状态做些什么;在 React 使用来自 api 的响应数组更新状态之前;状态将为“空”。

所以顺序是这样的

1.Initialize 初始值状态(空)

2.Renderreturn块

3.Update 状态(示例:setMovies([1,2,3]))

4.Re-渲染return块。

假设我的 return 块中有 {console.log(电影)}。我将在控制台中看到 2 个日志;第一个会说“null”(第 2 步),第二个会说“[1,2,3]”(第 4 步)

现在,如果我在 return 块中有 Movies.map 函数;它会抛出一个错误,说“TypeError: Movies.map is not a function”;因为 Movies 一开始是 null。

至于你的另一个问题:“未处理的拒绝(TypeError):无法读取未定义的 属性 'results'”

父对象为空时抛出该错误;在这种情况下;结果的父对象。无法确定是哪个“结果”在此处引发错误,因为您没有提供确切错误的行号。例如; data.results 正在扔这个;这意味着“数据”是空的并且没有作为子对象的结果。这很可能是两件事的结果;当我们判断响应对象模式错误时,(例如:response.data.movies.results 而不是 response.data.results)或者我们试图在填充它之前达到 data.results “例如:data = apiresponse.content ".

如果你能提供一个CodeSandbox;回答起来会容易得多。

在codesandbox之后编辑

更正错误:https://codesandbox.io/s/movies-app-angela-forked-ehr9u

错误:

  • MovieList .map 电影;由于我上面解释的原因,状态初始化为空;所以它会抛出错误;您只需在地图函数上方添加 {movies && movies.length > 0 ...} 1 步即可检查电影是否存在且不为空。

  • 在您的 searchMovies 函数中,您的 fetcher 调用会捕获 错误,但只有 console.logs;这会在 searchMovies 中产生问题 功能。因为即使响应为 null 或 errorcode,searchMovies 函数仍然继续工作,并错误地更新状态。

  • 您的搜索没有在视图中显示响应;因为 在 searchMovies 中调用之后;您需要提供对结果对象数组的直接访问,以便视图知道类型。 MoviesList 组件知道并呈现电影对象数组;但是在搜索之后,您将状态设置为也包含不同属性的对象;所以 MoviesList 不知道如何呈现结果。不久; response.data.results 而不是 response.data.

  • 您的 searchBar 组件,它实际上并不搜索确切的按键,而是搜索之前的 1 个。就像您尝试搜索“黑暗”一样;它搜索“dar”。当您搜索“d”时,它会搜索空字符串。您必须输入“dark”加 1 space 才能实际搜索“dark”。因此,api returns 422 在您键入的第一个字符出现无法处理的输入错误,因为它试图搜索空字符串。这是因为你更新状态,然后调用搜索api。但是更新状态是异步的,在将状态发送到 api fetcher 函数之前状态更新不会完成。如此简单的解决方案就是发送搜索获取器函数 event.target.value,而不是您正在更新的状态。

一个小提醒:现在更改您的 API 密钥;因为它暴露在网络上。

问题已解决。

这与 searchMovies api 调用有关,当我返回 api 响应时,我必须首先检查是否确实有响应全部。如果有响应,那么我想访问该响应中的 results 数组。

基本上在设置状态时这样做:

this.setState({ results: response && response.results });

而不是:

this.setState({ results: response.results });