显示来自API React/Redux的搜索结果

人气:57 发布:2023-01-03 标签: reactjs react-hooks redux react-redux redux-thunk

问题描述

我在我的应用程序中使用Redux进行状态管理--使用Reaction Hooks。我可以点击API并从我的操作创建者日志中获得如下屏幕截图:

以下是我试图在其中显示结果的组件的代码:

import { useState, useEffect } from "react";
import {Link} from 'react-router-dom';

import styled from "styled-components";

import {GoSearch} from 'react-icons/go';

import LoaderSpinner from "../components/LoaderSpinner";
import MovieItem from "../components/MovieItem";

import { RootStateOrAny, useDispatch, useSelector } from "react-redux";
import {fetchAllShows} from '../actions/movies';
import {searchMovieByTitle} from '../actions/search';

 const Home = () => {

   const [loading, setLoading] = useState(true);
   const [searchString, setSearchString] = useState('');
   const [isFromSearchResults, setIsFromSearchResults] = useState(false);

   const dispatch = useDispatch();
   const movies = useSelector((state: RootStateOrAny) => state.shows)
   const searchResults = useSelector((state: RootStateOrAny) => state.shows);

   useEffect(()=> {
      setLoading(true);
      dispatch(fetchAllShows());
      setIsFromSearchResults(false);
   }, [dispatch])

   const handleSearchChange = (e: any) => {
      e.preventDefault();
      setSearchString(e.target.value);
   }

   const findMovieByTitle = () => {
      dispatch(searchMovieByTitle(searchString));
      setIsFromSearchResults(true);
      setSearchString('');
   }

   console.log(isFromSearchResults);

   var start, max, paginatedArr=[], pageSize = 25;

   for(start = 0; max = movies.length, start < max; start += pageSize) {
      paginatedArr = movies.slice(start, start + pageSize);
   }

     return <HomeContainer>
       <div className="search-bar">
          <input 
            type="text" 
            placeholder="Search for a movie" 
            value={searchString}
            onChange={handleSearchChange}
          />
          <div className="search" onClick={findMovieByTitle}>
              <GoSearch />
          </div>
      </div>
       <div className="grid">
          {
            isFromSearchResults 
                ? <div>
                    {
                        searchResults.map((result: any, index: number) => {
                            console.log(result);
                            // console.log(result.show);
                            return <Link 
                                        key={index} 
                                        to={{pathname:`/movies/${result.show.id}`, 
                                        state: {movie: result.show}}} 
                                    >
                                      <MovieItem show={result.show} />
                                 </Link> 
                        })
                        // errors out in this return statement. It says the result (from array mapped out above is null) whereas the action creator is able to print out the full search queries
                    }
                </div>
                
                :  movies.length == 0 
                    ? <div className="loader">
                            <LoaderSpinner 
                                isLoading={loading} 
                                loadingText="Fetching Movies..."
                            />
                        </div>
                    // : movies.map((movie:any, index:number) => {
                    : paginatedArr.map((movie:any, index:number) => {
                        return <Link 
                                    to={{pathname:`/movies/${movie.id}`, 
                                    state: {movie: movie}}} key={index}
                                >
                            <MovieItem show={movie} />
                        </Link> 
                    })
           }
         </div>
      </HomeContainer>
  }

 export default Home;

以下是我的操作创建者进行搜索API调用的代码:

import {
   SEARCH_MOVIE_BY_TITLE,
} from './types';

import ShowsService from '../services/ShowsService';

export const searchMovieByTitle = (title: string) => async (dispatch: any) => {
try {
    let response = await ShowsService.searchMovieByTitle(title);
    console.log(typeof(response.data));
    // console.log(response.data);
    const promise = response.data.map((items: any) => {
        // console.log(items);
        return items;
    })
    const searchArr = await Promise.all(promise);
    console.log(searchArr);
    dispatch({type: SEARCH_MOVIE_BY_TITLE, payload: searchArr});
} catch (err) {
    console.log(err);
}
}
现在的问题在于试图解析搜索结果数组并将其显示为<MyComponent />的列表,并将电影作为道具传递。对于传递的每个项,它都显示为未定义。我如何解决此问题?

以下附加的错误日志示例:

推荐答案

我查看了您的代码,您的日志似乎只存在于搜索MovieByTitle操作中。似乎没有检查渲染视图中数据的可用性。通常,在执行回迁操作时,您还会在开始使用数据之前检查是否已成功回迁数据。

在您的代码中,这可以像这样完成:

<div className="grid">
  {isFromSearchResults && searchResults?.length ? ( // added check for searchResult here, to make sure it has data
    <div>
      {
        searchResults.map((result: any, index: number) => {
          console.log(result);
          console.log(result.show?.id); // it is suggested to also check if the id exists in all the result.show objects
          return (
            <Link
              key={index}
              to={{
                pathname: `/movies/${result.show?.id}`, // optionally add the "?." before id in order to avoid crushes if the id doesn't exist, though this depends on your backend logic; if they must always have an id, no need to add the "?."
                state: { movie: result.show },
              }}
            >
              <MovieItem show={result.show} />
            </Link>
          );
        })
        // errors out in this return statement. It says the result (from array mapped out above is null) whereas the action creator is able to print out the full search queries
      }
    </div>
  ) : movies.length == 0 ? (
    <div className="loader">
      <LoaderSpinner isLoading={loading} loadingText="Fetching Movies..." />
    </div>
  ) : (
    // : movies.map((movie:any, index:number) => {
    paginatedArr.map((movie: any, index: number) => {
      return (
        <Link
          to={{ pathname: `/movies/${movie.id}`, state: { movie: movie } }}
          key={index}
        >
          <MovieItem show={movie} />
        </Link>
      );
    })
  )}
</div>

如果仔细观察,我已经添加了数组长度的检查,确保在开始映射之前数据在其中。 还添加了对ID的检查,以查看是否所有的Result.show对象都具有该ID。

14