React Native中实现FlatList项跳转至对应页面并解决教室学生数据隔离问题
Ah, I see exactly what's going on here—you're storing all student data under the same generic student key in AsyncStorage, so every classroom reads and writes to that single shared dataset. That's why students added in Classroom A show up in B and C. Let's fix this by tying each classroom's student data to its unique ID, so we can keep them completely isolated.
First, Fix a Small Bug in MainMenu
Your delete classroom button has a tiny error—you're referencing classroom?.id instead of the actual item's ID. Let's correct that first in the FlatList renderItem:
<TouchableOpacity style={[styles.delete ]} onPress={() => deleteClassroom(item.id)}> <Icon name="remove" size={15} color={'#fff'} /> </TouchableOpacity>
Core Fix: Classroom-Specific Student Storage
The key change is to use the classroom's unique ID as part of the AsyncStorage key for its students. This way, each classroom gets its own separate storage bucket. Here's the updated Classroom component with all necessary changes:
/* eslint-disable prettier/prettier */ import React, { useState , useEffect } from 'react'; import { View, Text, TouchableOpacity, FlatList, Alert, TextInput, StyleSheet, } from 'react-native'; import Icon from 'react-native-vector-icons/MaterialIcons'; import AsyncStorage from '@react-native-async-storage/async-storage'; const Classroom = ( {navigation, route}) => { // Grab the current classroom's data from navigation params const currentClassroom = route.params; const [studentInput, setStudentInput] = useState(''); const [students, setStudents] = useState([]); // Dynamic storage key tied to the classroom's unique ID const storageKey = `students_${currentClassroom.id}`; useEffect(() => { getStudents(); // Optional: Update screen title to show the classroom name navigation.setOptions({ title: currentClassroom.Classroom }); }, []); useEffect(() => { saveStudents(students); }, [students]); const saveStudents = async (students) => { try { const stringifyStudents = JSON.stringify(students); // Use the classroom-specific key instead of generic 'student' await AsyncStorage.setItem(storageKey, stringifyStudents); } catch (error) { console.log(error); } }; const getStudents = async () => { try { // Fetch data using the classroom-specific key const storedStudents = await AsyncStorage.getItem(storageKey); if (storedStudents !== null) { setStudents(JSON.parse(storedStudents)); } } catch (error) { console.log(error); } }; const addStudent = () => { if (studentInput === ''){ Alert.alert('Error', 'Please input student name'); } else { const newStudent = { id: Math.random().toString(), Name: studentInput, }; setStudents([...students, newStudent]); setStudentInput(''); } }; const deleteStudent = (studentId) => { const updatedStudents = students.filter(item => item.id !== studentId); setStudents(updatedStudents); }; return ( <View style={styles.container}> {/* Fixed typo: style instead of styles={...} */} <TouchableOpacity onPress={()=> navigation.goBack()} style={styles.button}> <Text>Back</Text> </TouchableOpacity> {/* Show actual classroom name instead of placeholder */} <Text style={{fontWeight: 'bold', fontSize: 20}}>[ {currentClassroom.Classroom} ]</Text> <TextInput style={styles.input} placeholder={'Add Student Name'} value={studentInput} onChangeText={(text) => setStudentInput(text)} /> <TouchableOpacity onPress={()=> addStudent()} style={styles.button}> <Text>Add Student</Text> </TouchableOpacity> <FlatList style={styles.flatlist} data={students} keyExtractor = { (item) => item.id.toString() } renderItem={({ item }) => ( <View style={styles.listItem}> <View> <Text style={[styles.classText , {fontSize: 18}]}> {item?.Name} </Text> </View> <View > <TouchableOpacity style={[styles.delete ]} onPress={() => deleteStudent(item?.id)}> <Icon name="remove" size={15} color={'#fff'} /> </TouchableOpacity> </View> </View> )} /> </View> ); }; export default Classroom; const styles = StyleSheet.create({ container: { flex: 1, alignItems: 'center', justifyContent: 'center', backgroundColor: '#ecf0f1', padding: 8, }, input: { width: '70%', borderBottomWidth: 1, marginBottom: 20, }, button: { backgroundColor: 'lightblue', padding: 10, marginBottom: 10, }, listItem: { flexDirection: 'row', justifyContent: 'space-between', width: '70%', alignItems: 'center', }, delete: { backgroundColor: '#ff3333', padding: 5, color: '#fff', borderWidth: 1, borderColor: '#ff9999', borderRadius: 5, }, });
Key Changes Explained:
- Classroom-Specific Storage Key: We create a dynamic key like
students_{classroomId}so each classroom's data is stored separately. - Fetch/Save with Dynamic Key: All AsyncStorage operations now use this classroom-specific key instead of the generic
student. - Display Actual Classroom Name: Replaced the placeholder text with the actual classroom name from
route.params. - Fixed Container Style Typo: Corrected
styles={styles.container}tostyle={styles.container}which was breaking layout. - Optional Screen Title: Updated the navigation bar title to show the classroom name for better UX.
Optional: Clean Up Old Shared Data
Since you previously used the generic student key, you might want to clear that old data to avoid confusion. Add this one-time cleanup to the Classroom component's mount effect (then remove it after running once):
useEffect(() => { getStudents(); navigation.setOptions({ title: currentClassroom.Classroom }); // Clean up old shared student data (remove after first run) AsyncStorage.removeItem('student'); }, []);
内容的提问来源于stack exchange,提问作者BunnyHOPE

