Search code examples
javascriptreactjsreact-nativeasyncstorage

How to save route.params with asyncstorage?


Srry if the title makes no sense. Don't know a better title.

How can I save route.params items that I pass to my second screen using AsyncStorage?

In my first screen i have a bunch of data in a FlatList that can be opened with a Modal. Inside that Modal I have a TouchableOpacity that can send the data thats inside the Modal to my second screen. The data that has been passed to the second screen is passed to a FlatList. The data in the FlatList should be saved to AsyncStorage. Tried alot of things getting this to work, but only getting warning message undefined. Code below is the most recent progress.

Using React Navigation V5.

FIRST SCREEN

const [masterDataSource, setMasterDataSource] = useState(DataBase);
const [details, setDetails] = useState('');

<TouchableOpacity
   onPress={() => {
   const updated = [...masterDataSource];
   updated.find(
    (item) => item.id === details.id,
   ).selected = true;
    setMasterDataSource(updated);
    navigation.navigate('cart', {
    screen: 'cart',
    params: {
     items: updated.filter((item) => item.selected),
     },
    });
    setModalVisible(false);
   }}>
   <Text>Add to cart</Text>
</TouchableOpacity>

SECOND SCREEN

import React, { useEffect, useState } from 'react';
import { View, Text, FlatList, TouchableOpacity } from 'react-native';
import { useTheme } from '../Data/ThemeContext';

import AsyncStorage from '@react-native-async-storage/async-storage';

import Ionicons from 'react-native-vector-icons/Ionicons';

export default function ShoppingList({ route, navigation }) {
  const [shoppingList, setShoppingList] = useState([]);
  const { colors } = useTheme();

  const todo = () => {
    alert('Todo');
  };

  useEffect(() => {
    restoreShoppingListAsync();
  }, []);

  const shoppingListAsync = () => {
    const shoppingList = route.params && route.params.items;

    setShoppingList(list);
    storeShoppingList(list);
  };

  const asyncStorageKey = '@ShoppingList';

  const storeShoppingListAsync = (list) => {
    const stringifiedList = JSON.stringify(list);

    AsyncStorage.setItem(asyncStorageKey, stringifiedList).catch((err) => {
      console.warn(err);
    });
  };

  const restoreShoppingListAsync = () => {
    AsyncStorage.getItem(asyncStorageKey)
      .then((stringifiedList) => {
        console.log(stringifiedList);

        const parsedShoppingList = JSON.parse(stringifiedList);

        if (!parsedShoppingList || typeof parsedShoppingList !== 'object')
          return;

        setShoppingList(parsedShoppingList);
      })
      .then((err) => {
        console.warn(err);
      });
  };

  const RenderItem = ({ item }) => {
    return (
      <View>
        <TouchableOpacity
          style={{
            marginLeft: 20,
            marginRight: 20,
            elevation: 3,
            backgroundColor: colors.card,
            borderRadius: 10,
          }}>
          <View style={{ margin: 10 }}>
            <Text style={{ color: colors.text, fontWeight: '700' }}>
              {item.name}
            </Text>
            <Text style={{ color: colors.text }}>{item.gluten}</Text>
            <Text style={{ color: colors.text }}>{item.id}</Text>
          </View>
        </TouchableOpacity>
      </View>
    );
  };

  const emptyComponent = () => {
    return (
      <View style={{ alignItems: 'center' }}>
        <Text style={{ color: colors.text }}>Listan är tom</Text>
      </View>
    );
  };

  const itemSeparatorComponent = () => {
    return (
      <View
        style={{
          margin: 3,
        }}></View>
    );
  };

  return (
    <View
      style={{
        flex: 1,
      }}>
      <View
        style={{
          padding: 30,
          backgroundColor: colors.Textinput,
          elevation: 12,
        }}>
        <View style={{ flexDirection: 'row', justifyContent: 'space-between' }}>
          <TouchableOpacity onPress={() => navigation.goBack()}>
            <Ionicons name="arrow-back-outline" size={25} color="#fff" />
          </TouchableOpacity>
          <Text style={{ color: '#fff', fontSize: 20 }}>Inköpslista</Text>
          <TouchableOpacity>
            <Ionicons
              name="trash-outline"
              size={25}
              color="#fff"
              onPress={() => todo()}
            />
          </TouchableOpacity>
        </View>
      </View>
      <View style={{ flex: 1, marginTop: 30 }}>
        <FlatList
          data={shoppingList}
          renderItem={RenderItem}
          ListEmptyComponent={emptyComponent}
          ItemSeparatorComponent={itemSeparatorComponent}
          initialNumToRender={4}
          maxToRenderPerBatch={5}
          windowSize={10}
          removeClippedSubviews={true}
          updateCellsBatchingPeriod={100}
          showsVerticalScrollIndicator={true}
          contentContainerStyle={{ paddingBottom: 20 }}
        />
      </View>
    </View>
  );
}

Solution

  • As you are using async storage to maintain the cart. I would suggest an approach as below

    1. Update the asyn storage when new items are added to or removed from the cart
    2. Retrieve the items from the cart screen and show the items there

    Before you navigate store the items like below

            AsyncStorage.setItem(
              'Items',
              JSON.stringify(updated.filter((item) => item.selected))
            ).then(() => {
              navigation.navigate('Cart', {
                items: updated.filter((item) => item.selected),
              });
            });
    

    The cart screen would be something like below

    function Cart({ navigation, route }) {
    
      const [data,setData]=useState([]);
      React.useEffect(() => {
        async function fetchMyAPI() {
          const value = await AsyncStorage.getItem('Items');
          setData(JSON.parse(value));
        }
    
        fetchMyAPI();
      }, []);
    
      return (
        <View style={{ flex: 1, alignItems: 'center', justifyContent: 'center' }}>
          <Button title="Go back" onPress={() => navigation.goBack()} />
          <FlatList
            data={data}
            renderItem={RenderItem}
          />
        </View>
      );
    }
    

    Working Example https://snack.expo.io/@guruparan/cartexample