You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

React Native菜谱应用搜索页无法跳转至详情页求助

React Native菜谱应用搜索结果跳转问题

我开发的React Native菜谱应用,API数据获取、搜索功能都正常,但搜索结果列表无法跳转至菜谱详情页,首页的跳转功能却完全正常。

List.js代码

import React from "react";
import { Text, View, FlatList, SafeAreaView } from "react-native";
import styles from "../styles/styles";
import RecipeCard from "./RecipeCard";

const List = ({ searchPhrase, setClicked, data, navigation, screen }) => {
  const formattedSearchPhrase = searchPhrase.trim().replace(/\s/g, "").toUpperCase();

  const filteredData = data.filter((item) => {
    const formattedItemName = item.name?.trim().replace(/\s/g, "")?.toUpperCase();
    const formattedItemDetails = item.details?.trim().replace(/\s/g, "")?.toUpperCase();

    return formattedItemName?.includes(formattedSearchPhrase) || formattedItemDetails?.includes(formattedSearchPhrase);
  });

  const openRecipePageFromList = (recipe) => {     
    console.log('Navigating to screen:', recipe.screen);
  
    if (screen === 'SearchScreen') {
      navigation.navigate('SearchRecipePageScreen', { recipe: recipe });
    } else if (screen === 'FavoritesScreen') {
      navigation.navigate('FavoritesRecipePageScreen', { recipe: recipe });
    }
};

  const renderItem = ({ item }) => {
    const itemName = item.name?.trim();
    const itemDetails = item.details?.trim();

    if (!itemName && !itemDetails) {
      return null;
    }

    return (
      <RecipeCard
        key={item.id}
        recipe={{ name: itemName, details: itemDetails, thumbnail_url: item.thumbnail_url }}
        screen={'SearchScreen'}
        onPress={() => openRecipePageFromList(item)}
      />
    );
  };

  return (
    <SafeAreaView style={styles.list__container}>
      <View
        onStartShouldSetResponder={() => {
          setClicked(false);
        }}
      >
        <FlatList
          data={filteredData}
          renderItem={renderItem}
          keyExtractor={(item) => item.id}
          extraData={searchPhrase}
        />
      </View>
    </SafeAreaView>
  );
};

export default List;

RecipeCard.js代码

import React, { useState, useEffect } from 'react';
import { Text, View, Image, TouchableOpacity } from 'react-native';
import { useNavigation } from '@react-navigation/native';
import Icon from 'react-native-vector-icons/MaterialCommunityIcons';
import styles from '../styles/styles';
import AsyncStorage from '@react-native-async-storage/async-storage';

export default function RecipeCard({ recipe, screen }) {
    const navigation = useNavigation();
    const [isFavorite, setIsFavorite] = useState(false);

    useEffect(() => {
        const checkFavorite = async () => {
            try {
                const storedFavorites = await AsyncStorage.getItem('favoriteRecipes');
                if (storedFavorites !== null) {
                    const parsedFavorites = JSON.parse(storedFavorites);
                    const found = parsedFavorites.some((favRecipe) => favRecipe.id === recipe.id);
                    setIsFavorite(found);
                }
            } catch (e) {
                console.log(e);
            }
        };
        checkFavorite();
    }, [recipe.id]);

    const openRecipePage = () => {
        if (screen === 'HomeScreen') {
            navigation.navigate('HomeRecipePageScreen', { recipe: recipe });
        } else if (screen === 'SearchScreen') {
            navigation.navigate('SearchRecipePageScreen', { recipe: recipe });
        } else if (screen === 'FavoritesScreen') {
            navigation.navigate('FavoritesRecipePageScreen', { recipe: recipe });
        }
    };

    const handlePress = async () => {
        try {
            const storedFavorites = await AsyncStorage.getItem('favoriteRecipes');
            let favoriteRecipes = [];
            if (storedFavorites !== null) {
                favoriteRecipes = JSON.parse(storedFavorites);
            }
            if (isFavorite) {
                const index = favoriteRecipes.findIndex((favRecipe) => favRecipe.id === recipe.id);
                if (index > -1) {
                    favoriteRecipes.splice(index, 1);
                }
            } else {
                favoriteRecipes.push(recipe);
            }
            setIsFavorite(!isFavorite);
            await AsyncStorage.setItem('favoriteRecipes', JSON.stringify(favoriteRecipes));
        } catch (e) {
            console.log(e);
        }
    };

    return (
        <View>
            <TouchableOpacity onPress={openRecipePage}>
                <View style={styles.recipeCardContainer}>
                    <View style={styles.imageContainer}>
                        <Image style={styles.image} source={{ uri: recipe.thumbnail_url }} />
                        <TouchableOpacity onPress={handlePress}>
                        <Icon
                            name={isFavorite ? 'heart' : 'heart-outline'}
                            size={24}
                            color={isFavorite ? 'red' : 'black'}
                            style={styles.heartIcon}
                        />
                    </TouchableOpacity>
                    </View>
                    <Text style={styles.recipeCardTextFrontPage}>{recipe.name}</Text>
                </View>
            </TouchableOpacity>
        </View>
    );
}

问题定位与修复方案

核心问题

  1. 传递的Recipe对象缺失关键属性:在List.js的renderItem中,你手动拼接的recipe对象只包含name、details、thumbnail_url,缺少id。这会导致RecipeCard中依赖id的收藏判断失效,同时传递给详情页的菜谱数据不完整,可能引发跳转逻辑异常。
  2. 冗余的跳转函数未被使用:List.js中定义了openRecipePageFromList并传递给RecipeCard的onPress属性,但RecipeCard内部并未调用该props,而是使用自身的openRecipePage函数,导致这个自定义跳转逻辑完全无效。

修复步骤

  1. 修正List.js中RecipeCard的recipe传递
    直接传递完整的item对象(或至少包含所有必要属性),不要手动截断:

    return (
      <RecipeCard
        key={item.id}
        recipe={item} // 传递完整的item,保留所有属性
        screen={'SearchScreen'}
      />
    );
    

    若担心冗余属性,可解构出需要的字段并保留id:

    const { id, name, details, thumbnail_url } = item;
    return (
      <RecipeCard
        key={id}
        recipe={{ id, name: name?.trim(), details: details?.trim(), thumbnail_url }}
        screen={'SearchScreen'}
      />
    );
    
  2. 修复RecipeCard的事件冒泡问题
    爱心按钮嵌套在跳转卡片的TouchableOpacity中,点击爱心时会触发外层的跳转逻辑,需添加事件阻止:

    <TouchableOpacity onPress={(e) => {
      e.stopPropagation(); // 阻止事件冒泡到外层卡片
      handlePress();
    }}>
    
  3. 验证导航栈配置
    确认SearchRecipePageScreen已正确注册到导航栈中,且能正常接收route.params.recipe参数。


内容的提问来源于stack exchange,提问作者Krista

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.24 11:57:02