问题描述
我在我的应用程序中使用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。