导航到附加了平面列表的新屏幕会导致崩溃

问题描述 投票:0回答:0

我是新手。我正在尝试使用 MoviesScreen 和 MovieDetailsScreen 构建两个屏幕的电影应用程序。 MoviesScreen 显示带有平面列表的电影列表,MovieDetailsScreen 显示电影信息,还使用平面列表显示该电影中的演员。 MoviesScreen 是 MoviesDetailsScreen 的父组件,当 MoviesDetailsScreen 导航回 MoviesScreen 时,按下任何电影都会导致崩溃。我认为这是一个平面列表问题,因为 MoviesDetailsScreen 有一个演员平面列表,并且由于数据是远程收集的,所以这两个平面列表无法真正调整。我该如何解决这个问题?这是我的 MoviesScreen:

function MoviesScreen({ route, navigation }) {
  const [isLoading, setIsLoading] = useState(true);
  const [error, setError] = useState();
  const { moviesParam, queryString } = route.params || {};
  const [movies, setMovies] = useState([]);
  const [currentPage, setCurrentPage] = useState(1);
  const [totalPages, setTotalPages] = useState(1);
  const flatListRef = useRef(null);

  useLayoutEffect(() => {
    setIsLoading(true);
    if (moviesParam === "query" && queryString !== "") {
      // execute the getItemsByQuery function with the queryString value
      async function getItems() {
        try {
          const movies = await FetchMoviesByQuery(queryString);
          setMovies(movies);
        } catch (error) {
          setError("Searching is not available at this time!");
        } finally {
          setIsLoading(false);
        }
      }
      getItems();
    } else {
      setIsLoading(true);
    }
  }, [queryString, navigation]);

  // Fetch movies when currentPage or moviesParam changes
  useLayoutEffect(() => {
    async function getMovies() {
      let remainingUrl = "";
      if (moviesParam == "trending") {
        remainingUrl = "trending/movie/week?api_key=";
      } else {
        remainingUrl = `movie/${moviesParam}?api_key=`;
      }
      try {
        const { movies, totalPages } = await FetchMovies(
          remainingUrl,
          currentPage
        );
        setMovies((prevMovies) => [...prevMovies, ...movies]);
        setTotalPages(totalPages);
      } catch (error) {
        setError("Movies List is not available at this time!");
      } finally {
        setIsLoading(false);
      }
    }

    if (
      (moviesParam === "query" && queryString !== "") ||
      currentPage > totalPages
    ) {
      // do nothing
      return;
    }

    getMovies();
  }, [moviesParam, currentPage]);

  function errorHandler() {
    setError(null);
  }

  if (error && !isLoading)
    return <ErrorOverlay message={error} onConfirm={errorHandler} />;
  if (isLoading) return <LoadingOverlay />;
  if (movies.length === 0)
    return <EmptyListOverlay navigation={navigation} screenName="Movies Tab" />;

  function renderMovies(itemData) {
    function pressHandler() {
      navigation.navigate("Movie Details", {
        movieId: itemData.item.id,
      });
    }
    return (
      <>
        <MovieList {...itemData.item} onPress={pressHandler} />
      </>
    );
  }

  return (
    <>
      <FlatList
        ref={flatListRef}
        data={movies}
        keyExtractor={(item) => item.id}
        renderItem={renderMovies}
        horizontal={false}
        numColumns={3}
        onEndReached={() => {
          if (currentPage < totalPages) {
            setCurrentPage(currentPage + 1);
          }
        }}
        onEndReachedThreshold={0.5}
      />

      <ReloadButton
        navigation={navigation}
        screenName="Movies Tab"
        flatListRef={flatListRef}
      />
    </>
  );
}"

电影细节屏幕:

function MovieDetailsScreen({ route, navigation }) {
  const { movieId } = route.params;
  let remainingUrl = `movie/${movieId}?api_key=`;
  const [movie, setMovie] = useState([]);
  const [actors, setActor] = useState([]);
  const [isLoading, setIsLoading] = useState(true);
  const [isLoadingActors, setIsLoadingActors] = useState(true);
  const [error, setError] = useState();
  const [isMovieLoaded, setIsMovieLoaded] = useState(false);
  const flatListRef = useRef(null);

  const memoizedMovieDetails = useMemo(() => {
    return <MovieDetails {...movie} />;
  }, [movie]);

  useLayoutEffect(() => {
    async function getMovie() {
      setIsLoading(true);
      try {
        const movie = await FetchMovieDetails(remainingUrl);
        setMovie(movie);
        setIsMovieLoaded(true);
        navigation.setOptions({
          title: `${movie.title}`,
        });
      } catch (error) {
        setError("Movie Details Are not Available");
      }
      setIsLoading(false);
    }
    getMovie();
  }, [remainingUrl, movieId, navigation]);

  useLayoutEffect(() => {
    if (!isMovieLoaded) return;
    setIsLoadingActors(true);
    async function getActorInformation() {
      try {
        const actorDetails = await FetchActorsByMovie(movieId);
        setActor(actorDetails);
      } catch (error) {
        setError("Star Casts are not available");
      }
      setIsLoadingActors(false);
    }
    getActorInformation();
    return () => {
      setActor([]); // <-- add cleanup function to clear the actors state
    };
  }, [movieId, isMovieLoaded]);

  function errorHandler() {
    setError(null);
  }

  if (error && !isLoading) {
    return <ErrorOverlay message={error} onConfirm={errorHandler} />;
  }
  if (isLoading || isLoadingActors || !isMovieLoaded) {
    return <LoadingOverlay />;
  }

  return (
    <View style={styles.container}>
      {isMovieLoaded && (
        <MovieDetailsTop
          movie={movie}
        />
      )}
      {isMovieLoaded && !isLoadingActors && (
        <FlatList
          ref={flatListRef}
          data={actors}
          windowSize={5}
          initialNumToRender={3}
          maxToRenderPerBatch={6}
          removeClippedSubviews={true}
          keyExtractor={(item) => item.id.toString()}
          renderItem={(itemData) => (
            <ActorList itemData={itemData} navigation={navigation} />
          )}
          horizontal={false}
          numColumns={3}
          ListHeaderComponent={<>{memoizedMovieDetails}</>}
        />
      )}
      <MinimizableText text={`Overview: ${movie.overview}`} />
    </View>
  );
}
export default MovieDetailsScreen;

我尝试设置多个加载条件,但没有一个有效。作为参考,我在 MovieDetailsScreen 中保留了加载条件,我也在 MoviesScreen 上尝试了它们,但它们并没有解决问题。还尝试使用 useEffect 而不是 useLayoutEffect,但没有解决问题。

react-native react-hooks react-navigation react-native-flatlist
© www.soinside.com 2019 - 2024. All rights reserved.