我是个新手,但我在学习。我目前正在构建一个应用程序,我的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",
},
});
2条答案
按热度按时间2vuwiymt1#
我将我的renderItem函数从Mapjson列表改为一次只接受一个项目。
uajslkp62#
useMemo和useCallback都可用于优化FlatList的renderItem函数的呈现性能,但它们的用途不同。因此,如果renderItem函数不依赖于任何其他值或状态更改,则使用useMemo不会提供任何性能优势。但是,如果renderItem函数是为数据数组中的每一项调用的回调函数,则使用
useCallback
存储函数并在依赖项数组中提供值可以提供性能优势。例如:
const addTodo = useCallback(()=〉{ setTodos((t)=〉[...t,“New Todo”]););