Search code examples
react-nativereact-hooksnavigationasyncstorage

React Native async storage problem. It does only load the item before


I'm programming a react native app, which calculates the average of the grades. There you can create subjects and for each subject you can add grades. For that I have difference screens. I safe it in a dictonary, which I load it into the async storage. For example: {subject 1: [grades], subject 2: [grades] }. In real life: {math: [1, 4,2], english:[5,2]}. But now I have the problem, when I add a subject, it loads the subject before and when I add then a new subject, only then it loading it.

Here is a video with the problem and the full code(it's the same video): https://www.dropbox.com/s/4yqzl22zannb9ln/reactnativeproblem.mp4?dl=0 https://drive.google.com/file/d/1Wi37lmMCgYOAFQSOMOQebCWkQSsFiPaz/view?usp=sharing

Here is the code for app.js:

    import { React, useEffect, useState } from "react";
import { StyleSheet } from "react-native";
import { NavigationContainer } from "@react-navigation/native";
import { createNativeStackNavigator } from "@react-navigation/native-stack";
import Homescreen from "./screens/Homescreen";
import NewSubject from "./screens/NewSubject";
import ShowSubject from "./screens/ShowSubject";
import AsyncStorage from "@react-native-async-storage/async-storage";

const Stack = createNativeStackNavigator();

export default function App() {
  let [dict, setDict] = useState({});

  useEffect(() => {
    loadDictionary().then(res => {
      setDict(res);
    });
  }, []);

  useEffect(() => {
    safeDictionary();
  }, [dict]);

  async function loadDictionary() {
    const value = await AsyncStorage.getItem('dict');
    try {
      if (value) {
        return JSON.parse(value);
      }
      return ({});
    } catch (error) {
      console.log("GET ERROR AT LOAD DICTONARY: ", error)
    }
  }

  async function safeDictionary() {
    try {
      await AsyncStorage.setItem("dict", JSON.stringify(dict));
    } catch (error) {
      console.log("GET ERROR AT SAFE DICTONARY:", error);
    }
  }

  return (
    <NavigationContainer>
      <Stack.Navigator>
        <Stack.Screen
          name="Home"
          component={Homescreen}
          options={{ title: "Grades Calculator" }}
          initialParams={{ dict, setDict }}
        />
        <Stack.Screen name="New Subject" component={NewSubject} initialParams={{ dict, setDict }} />
        <Stack.Screen name="Subject" component={ShowSubject} initialParams={{ dict, setDict }}/>
      </Stack.Navigator>
    </NavigationContainer>
  );
}

I hope anybody can help me :)


Solution

  • Passing dynamic dict value as initialParams is not recommended. Adding and displaying subjects should be handled by their respective screens.

    import { React, useEffect, useState } from "react";
    import { StyleSheet, View, Button, TextInput, Text } from "react-native";
    import { NavigationContainer } from "@react-navigation/native";
    import { createNativeStackNavigator } from "@react-navigation/native-stack";
    import AsyncStorage from "@react-native-async-storage/async-storage";
    
    const Stack = createNativeStackNavigator();
    
    function HomeScreen(props) {
      return (
        <View>
          <Button
            title="Add Subject"
            onPress={() => props.navigation.navigate("NewSubject")}
          />
        </View>
      );
    }
    
    function NewSubject(props) {
      const [subject, setSubject] = useState("");
    
      async function loadDictionary() {
        const value = await AsyncStorage.getItem("dict");
        try {
          if (value) {
            return JSON.parse(value);
          }
          return [];
        } catch (error) {
          console.log("GET ERROR AT LOAD DICTONARY: ", error);
        }
      }
    
      async function saveDictionary() {
        if (!subject) return;
        try {
          const prev = await loadDictionary();
    
          const next = [...prev, subject];
          await AsyncStorage.setItem("dict", JSON.stringify(next));
    
          props.navigation.navigate("Subject");
        } catch (error) {
          console.log("GET ERROR AT SAFE DICTONARY:", error);
        }
      }
      return (
        <View style={{ padding: 20 }}>
          <View>
         
            <TextInput
              placeholder="Type subject..."
              style={{ padding: 5, borderWidth: 1 }}
              onChangeText={setSubject}
            />
          </View>
    
          <View style={{ paddingVertical: 10 }}>
            <Button title="Add Subject" onPress={saveDictionary} />
            <Button
              title="Cancel"
              onPress={() => props.navigation.goBack()}
              color="black"
            />
          </View>
        </View>
      );
    }
    
    function ShowSubject(props) {
      let [dict, setDict] = useState([]);
      async function loadDictionary() {
        const value = await AsyncStorage.getItem("dict");
        try {
          if (value) {
            return JSON.parse(value);
          }
          return {};
        } catch (error) {
          console.log("GET ERROR AT LOAD DICTONARY: ", error);
        }
      }
    
      useEffect(() => {
        loadDictionary().then((res) => {
          setDict(res);
        });
      }, []);
    
      return (
        <View>
          {dict.map((subject) => (
            <Text key={subject}> {subject} </Text>
          ))}
          <View>
            <Button
              title="Add Subject"
              onPress={() => props.navigation.navigate("NewSubject")}
            />
          </View>
        </View>
      );
    }
    export default function App() {
      return (
        <NavigationContainer>
          <Stack.Navigator>
            <Stack.Screen
              name="Home"
              component={HomeScreen}
              options={{ title: "Grades Calculator" }}
            />
            <Stack.Screen
              name="NewSubject"
              options={{ title: "New Subject" }}
              component={NewSubject}
            />
            <Stack.Screen name="Subject" component={ShowSubject} />
          </Stack.Navigator>
        </NavigationContainer>
      );
    }
    
    
    

    Live Demo - https://snack.expo.dev/@emmbyiringiro/d25e82