React Native 我正在尝试memoize,以避免flatlist值渲染太多次

4szc88ey  于 2023-05-07  发布在  React
关注(0)|答案(2)|浏览(141)

我是个新手,但我在学习。我目前正在构建一个应用程序,我的renderItem函数在每次渲染后都被调用,这导致我的平面列表有重复的内容。我尝试memoize renderItem,但当我调用memorizedrenderItem时,我得到一个错误,说“rendered more hooks than previous render”。我该怎么解决这个问题?我最终只想让我的平面列表呈现适当数量的项,而不是所有的重复项。我已经附上了一个片段,然后我的完整代码。

const renderItem = () => {
      console.log("renderItem called");
      return result.map((recipe, index) => (
        // when you press this, go to a page that displays recipe details
        <TouchableOpacity
          onPress={() =>
            navigation.navigate("viewRecipeScreen", {
              recipe: recipe,
            })
          }
          key={index}
        >
          <Image
            source={{
              uri:
                recipe?.imagepath === "empty"
                  ? "https://static.vecteezy.com/system/resources/previews/005/337/799/original/icon-image-not-found-free-vector.jpg"
                  : recipe?.imagepath,
            }}
            style={styles.recipeImage}
          />
        </TouchableOpacity>
      ));
    };
    
    const memorenderItem = useMemo(() => renderItem(), []);
import React, {
    useEffect,
    useContext,
    useState,
    useCallback,
    useMemo,
  } from "react";
  import {
    View,
    Text,
    StyleSheet,
    TextInput,
    Image,
    FlatList,
    TouchableOpacity,
  } from "react-native";
  import Button from "react-native-button";
  import { auth } from "../firebase/firebase";
  import { onAuthStateChanged, signInWithEmailAndPassword } from "firebase/auth";
  import { doc, getDoc, updateDoc, arrayUnion } from "firebase/firestore";
  import { db } from "../firebase/firebase";
  import { AuthContext } from "../navigation/AuthProvider";
  
  export function UserHome({ navigation }) {
    const { user, setName, setUserName, userName, setBioText, logout } =
      useContext(AuthContext);
    const [queryText, setQueryText] = useState("");
    const [result, setResult] = useState([]);
    const [loading, setLoading] = useState(true);

    const [searchPressed, setSearchPressed] = useState(false);
    const [likes, setLikes] = useState("");
    const [dislikes, setDislikes] = useState("");
    const [survey, setSurvey] = useState(null);
  
    const handleSignOut = () => {
      logout();
    };
  
    const handleInputChange = (text) => {
      setQueryText(text);
    };
  
    useEffect(() => {
      const getName = async (userId) => {
        const docRef = doc(db, "userInfo", userId);
        const docSnap = await getDoc(docRef);
        const full_name = docSnap.get("fullname");
        const user_name = docSnap.get("username");
        const bio_Text = docSnap.get("bio");
        const likes = docSnap.get("faveRecs");
        setLikes(likes);
        const dislikes = docSnap.get("badRecs");
        const surveyResults = docSnap.get("tolerance_questionnaire");
        setSurvey(surveyResults);
        setDislikes(dislikes);
        if (docSnap.exists()) {
          setName(full_name);
          setUserName(user_name);
          setBioText(bio_Text);
        } else {
          console.log("No username, bio, or full name found");
        }
      };
      onAuthStateChanged(auth, (user) => {
        if (user) {
          getName(user.uid);
        }
      });
    }, []);
  
    useEffect(() => {
      const fetchRecipes = async () => {
        try {
          // create body for lambda function
          const palette_body = {
            body: {
              recipeCategory: null,
              user_info: { likes, dislikes, survey },
            },
          };
  
          const response = await fetch(
            `https://25jg62s1m6.execute-api.us-east-1.amazonaws.com/test/kohoquery/palette_analyzer`,
            {
              method: "POST",
              body: JSON.stringify(palette_body),
              headers: {
                "Content-Type": "application/json",
              },
            }
          );
          const result_data = await response.json();
  
          setResult(JSON.parse(result_data.body));
  
          console.log("yay!");
          setLoading(false);
        } catch (error) {
          console.log("Error parsing JSON data!!!:", error);
          //setError(error);
          setLoading(false);
        }
  
        try {
          if (queryText) {
            const response = await fetch(
              `https://25jg62s1m6.execute-api.us-east-1.amazonaws.com/test/kohoquery?queryText=${queryText}`
            );
            const data = await response.json();
            setSearchResults(data.slice(0, 4));
  
            navigation.navigate("recipeDetailsScreen", {
              recipe: data.slice(0, 4),
            });
          }
        } catch (error) {
          console.error(error);
          console.log("erorrrr");
        }
      };
      fetchRecipes();
    }, [searchPressed]);
    // I want to fetch 5 recipes from our db
    // I want to render those 5 recipes in a slide show to be displayed at all times
    //console.log("yayyy again", result[0]);
    if (loading) {
      return <Text>Loading...</Text>;
    }
  
   
  
    const renderItem = () => {
      console.log("renderItem called");
      return result.map((recipe, index) => (
        // when you press this, go to a page that displays recipe details
        <TouchableOpacity
          onPress={() =>
            navigation.navigate("viewRecipeScreen", {
              recipe: recipe,
            })
          }
          key={index}
        >
          <Image
            source={{
              uri:
                recipe?.imagepath === "empty"
                  ? "https://static.vecteezy.com/system/resources/previews/005/337/799/original/icon-image-not-found-free-vector.jpg"
                  : recipe?.imagepath,
            }}
            style={styles.recipeImage}
          />
        </TouchableOpacity>
      ));
    };
    
    const memorenderItem = useMemo(() => renderItem(), []);
    return (
      <View style={styles.container}>
        <View style={styles.headerContainer}>
          <Image
            source={require("../assets/kohomainlogo.png")}
            style={styles.logo}
          />
          <View style={styles.welcomeContainer}>
            <Text style={styles.welcomeText}>Signed in as: @{userName}!</Text>
            <Text style={styles.cookText}>What would you like to cook?</Text>
          </View>
          <TextInput
            style={styles.input}
            onChangeText={handleInputChange}
            value={queryText}
            placeholder="Enter your dish name"
            placeholderTextColor={"grey"}
            returnKeyType="search"
            onSubmitEditing={() => setSearchPressed(!searchPressed)}
          />
        </View>
  
        <View style={styles.recipeContainer}>
          <Text style={styles.recipeTitle}>We think you'd like these!</Text>
          <FlatList
            data={result}
            renderItem={renderItem}
            keyExtractor={(item, index) => index.toString()}
            horizontal={true}
            windowSize={1}
          />
        </View>
  
        <View style={styles.recipeContainerPopular}>
          <Text style={styles.recipeTitle}>Most Popular</Text>
        </View>
  
        <View style={styles.bottomContainer}>
          <Button
            containerStyle={{
              padding: 10,
              height: 45,
              overflow: "hidden",
              borderRadius: 20,
              backgroundColor: "#8252ff",
            }}
            style={{
              fontSize: 18,
              color: "white",
              textAlign: "center",
            }}
            onPress={handleSignOut}
          >
            Sign Out
          </Button>
        </View>
      </View>
    );
  }
  
  const styles = StyleSheet.create({
    container: {
      flex: 1,
      alignItems: "center",
      justifyContent: "center",
    },
    headerContainer: {
      backgroundColor: "#fff",
      height: 80,
      justifyContent: "center",
      alignItems: "center",
      borderBottomWidth: 1,
      borderBottomColor: "#ccc",
      width: "100%",
    },
    logo: {
      width: 150,
      height: 75,
      resizeMode: "contain",
      marginTop: 150,
    },
    bottomContainer: {
      flex: 1,
      justifyContent: "flex-end",
      marginBottom: 20,
    },
    welcomeContainer: {
      paddingLeft: 10,
    },
    welcomeText: {
      fontSize: 18,
    },
    cookText: {
      fontSize: 18,
      fontWeight: "bold",
    },
    input: {
      height: 40,
      width: "80%",
      borderColor: "gray",
      borderWidth: 1,
      marginBottom: 20,
      padding: 10,
      borderRadius: 10,
      marginTop: 10,
      backgroundColor: "white",
    },
    recipeContainer: {
      flexDirection: "column",
      justifyContent: "space-around",
      alignItems: "center",
      marginTop: 150,
      width: "100%",
    },
    recipeContainerPopular: {
      flexDirection: "column",
      justifyContent: "space-around",
      alignItems: "center",
      marginTop: 20,
      width: "100%",
    },
    recipeImage: {
      width: 400,
      height: 200,
      resizeMode: "cover",
      borderRadius: 10,
      marginHorizontal: 5,
    },
    recipeTitle: {
      fontSize: 24,
      fontWeight: "bold",
      marginBottom: 10,
      marginTop: 10,
      textAlign: "left",
      alignItems: "flex-start",
    },
  });
2vuwiymt

2vuwiymt1#

我将我的renderItem函数从Mapjson列表改为一次只接受一个项目。

const renderItem = ({ item }) => (
    <TouchableOpacity
      onPress={() =>
        navigation.navigate("viewRecipeScreen", {
          recipe: item,
        })
      }
    >
      <Image
        source={{
          uri:
            item?.imagepath === "empty"
              ? "https://static.vecteezy.com/system/resources/previews/005/337/799/original/icon-image-not-found-free-vector.jpg"
              : item?.imagepath,
        }}
        style={styles.recipeImage}
      />
    </TouchableOpacity>
  );
uajslkp6

uajslkp62#

useMemo和useCallback都可用于优化FlatList的renderItem函数的呈现性能,但它们的用途不同。因此,如果renderItem函数不依赖于任何其他值或状态更改,则使用useMemo不会提供任何性能优势。但是,如果renderItem函数是为数据数组中的每一项调用的回调函数,则使用useCallback存储函数并在依赖项数组中提供值可以提供性能优势。
例如:
const addTodo = useCallback(()=〉{ setTodos((t)=〉[...t,“New Todo”]););

相关问题