Home > Software engineering >  React Native key in AsyncStorage
React Native key in AsyncStorage

Time:09-21

I am new in React Native and I want to apply AsyncStorage in my project. I am doing a project where I can add Classroom in the flatlist, then in each Classroom, I can add Student names of each class using flatlist. Asyncstorage will be applied in both Classroom list and Student list.

My expectation is , I add classroom A , classroom B and classroom C , then when I pressed Clasroom A, I can add the name of students and when I go to classroom B , the name list is still empty waiting for me to fill the list.

My actual result is , after I add studentA , studentB , studentC in classroom A, when I go to classroom B, the 3 students in classroom A is still available in the list of classroom B.

So , how can I fix this to meet my requirement or it would be very helpful and much appreciated if you could provide a code with explanation. Thank you very much in advance

this is my code for the MainMenu.js where I need to add classroom :

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';
import { useNavigation } from '@react-navigation/native';
import { CardStyleInterpolators } from '@react-navigation/stack';

export default function MainMenu(){
  const [classroomInput, setClassroomInput] = useState('');
  const [classroom, setClassroom] = useState([]);

  const navigation = useNavigation();

  useEffect(() => {
    getClassroom();
  }, []);
  useEffect(() => {
    saveClassroom(classroom);
  }, [classroom]);


  const saveClassroom = async (classroom) => {
    try {
      const stringifyClassroom = JSON.stringify(classroom);
      await AsyncStorage.setItem('classroom', stringifyClassroom);
    } catch (error) {
      console.log(error);
    }
  };

  const getClassroom = async () => {
    try {
      const classrooms = await AsyncStorage.getItem('classroom');
      if (classrooms !== null) {
        setClassroom(JSON.parse(classrooms));
      }
    } catch (error) {
      console.log(error);
    }
  };

  const addClassroom = () => {
    if (classroomInput === ''){
      Alert.alert('Error', 'Please input class');
    } else {
      const newClassroom = {
        id: Math.random().toString(),
        Classroom: classroomInput,
      };
      setClassroom([...classroom,newClassroom]);
      setClassroomInput('');

    }
  };

  const deleteClassroom = (classroomId) => {
    const newClassrooms = classroom.filter(item => item.id !== classroomId);
    setClassroom(newClassrooms);
  };


  return (
    <View style={styles.container}>
      <TextInput
      style={styles.input}
      placeholder={'Add Classrooms'}
      value={classroomInput}
      onChangeText={(text) => setClassroomInput(text)}
      />
      <TouchableOpacity onPress={() => addClassroom()} style={styles.button}>
        <Text>Add Classroom</Text>
      </TouchableOpacity>
      <FlatList
        style={styles.flatlist}
        data={classroom}
        keyExtractor = { (item) => item.id.toString() }
        renderItem={({ item }) => (
          <TouchableOpacity onPress= {() => navigation.navigate('Classroom', item)}  >
          <View style={styles.listItem}>
            <View>
              <Text>
            {item?.Classroom}
              </Text>
            </View>
            <View >
              <TouchableOpacity style={[styles.delete ]} onPress={() => deleteClassroom(item?.id)}>
                <Icon name="remove" size={15} color={'#fff'} />
              </TouchableOpacity>
            </View>
          </View>
          </TouchableOpacity>
        )}
      />
    </View>
  );
}

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,
  },
  delete: {
    backgroundColor: '#ff3333',
    padding: 5,
    color: '#fff',
    borderWidth: 1,
    borderColor: '#ff9999',
    borderRadius: 5,
  },
  listItem: {
    flexDirection: 'row',
    justifyContent: 'space-between',
    width: '70%',
    alignItems: 'center',
  },
});

and this is the Classroom.js where I will add the student list

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';
import { useRoute } from '@react-navigation/core';


const Classroom = ( {navigation}) => {
    const [studentInput, setStudentInput] = useState('');
    const [student, setStudent] = useState([]);

    const route = useRoute();

    useEffect(() => {
        getStudent();
      }, []);
      useEffect(() => {
        saveStudent(student);
      }, [student]);

      const saveStudent = async (student) => {
        try {
          const stringifyStudent = JSON.stringify(student);
          await AsyncStorage.setItem('student', stringifyStudent);
        } catch (error) {
          console.log(error);
        }
      };

      const getStudent = async () => {
        try {
          const students = await AsyncStorage.getItem('student');
          if (students !== null) {
            setStudent(JSON.parse(students));
          }
        } 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,
          };
          setStudent([...student,newStudent]);
          setStudentInput('');

        }
      };

    const deleteStudent = (studentId) => {
        const newStudent = student.filter(item => item.id !== studentId);
        setStudent(newStudent);
    };

    return (
        <View styles={styles.container}>
            <TouchableOpacity onPress={()=> navigation.goBack()} style={styles.button}>
                <Text>Back</Text>
            </TouchableOpacity>
            <Text style={{fontWeight: 'bold', fontSize: 20}}>{route.params.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={student}
            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,
      },
  });

CodePudding user response:

Your problem is you are setting all the students with the same key student.

What you need to do instead is use the class name to set a dynamic key for your storage if your class names are unique otherwise you need to use something like uuid in order to create unique ids for your classes.

for example you can do this in your save student function

const saveStudent = async (student) => {
  try {
    const stringifyStudent = JSON.stringify(student);
    await AsyncStorage.setItem(`class${class.name}:students`, stringifyStudent);
  } catch (error) {
    console.log(error);
  }
};

and do this for your get student function

const getStudent = async () => {
  try {
    const students = await AsyncStorage.getItem(`class${class.name}:students`);
    if (students !== null) {
      setStudent(JSON.parse(students));
    }
  } catch (error) {
    console.log(error);
  }
};

Also try using uuid package instead of Math.random for your id creation. It's true that getting same numbers using Math.random is very unlikely but it is still possible but with uuid this is impossible.

  • Related