Home > Mobile >  Expo SecureStore not saving correctly (React native, typescript)
Expo SecureStore not saving correctly (React native, typescript)

Time:12-02

I'm working on a mobile phone application with Stripe and Expo Bar Code Scanner. When you start the application, if you gave the permissions for using the camera, you will can scan bar codes. Bar Codes only contains the id of the scanned item. If it exists, two buttons ( /-) will appear in order to choose the amount for the item. If it doesn't exists, nothing happens. When the amount changes, I save in SecureStore the id of the item as the key and the amount as the value.

The problem is when I move on others screens (with React Navigation) and I came back to scan and I rescan the same item, the amount resets to 0. If you don't give the permissions for the camera, it displays a list of available items when you can choose the amount ( /-) buttons and similar problem.

Here the concerned two files :

ItemListComponent.tsx

import { Button, FlatList, View, Text } from 'react-native';
import * as SecureStore from 'expo-secure-store';
import { useState } from 'react';

export const ItemComponent = (props: any) => {
  const [amount, setAmount] = useState<number>(0);

  const getAmount = async () => {
    const amount = await SecureStore.getItemAsync(props.item.id.toString());

    if (amount) {
      setAmount(parseInt(amount));
    }
    getAmount();
  }

  const save = async () => {
    await SecureStore.setItemAsync(props.item.id.toString(), amount.toString());
  }

  return (
    <View>
      <Text>{props.item.name}</Text>
      <Button
        onPress={() => {
          setAmount(amount   1);
          save();
        }}
        title=' '
      />
      {amount > 0 &&
        <Button
          onPress={() => {
            setAmount(amount - 1);
            save();
          }}
          title='-'
        />
      }
    </View>
  );
};

export const ItemListComponent = (props: any) => {
  return (
    <FlatList
      data={props.items}
      renderItem={({ item }) =>
        <ItemComponent key={item.id} item={item} />
      }
    />
  );
};

BarCodeScannerComponent.tsx

import { BarCodeScanner } from 'expo-barcode-scanner';
import { useState } from 'react';
import { StyleSheet } from 'react-native';
import { ItemComponent } from './ItemListComponent';
import Items from '../models/ItemsModel';

export const BarCodeScannerComponent = () => {
  const [item, setItem] = useState<Items>();

  const getItem = async ({ data }: any) => {
    const response = await fetch(`http://192.168.1.81:8000/items/${data}`, {
      method: 'GET',
      headers: {
        'Content-Type': 'application/json',
      },
    });
    if (response.ok) {
      const json = await response.json();
      setItem(json);
    }
  }

  return (
    <View style={styles.container}>
      <BarCodeScanner
        onBarCodeScanned={getItem}
        style={StyleSheet.absoluteFillObject}
      />
      {(item !== null && item !== undefined) && <ItemComponent key={item.id} item={item} />}
    </View>
  );
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    flexDirection: 'column',
    justifyContent: 'center',
  },
});

Thanks for help !

CodePudding user response:

It looks like you never call getAmount, and if you did call it you'd get infinite recursion.

const getAmount = async () => {
  const amount = await SecureStore.getItemAsync(props.item.id.toString());

  if (amount) {
    setAmount(parseInt(amount));
  }
  getAmount();
}

should be

const getAmount = async () => {
  const amount = await SecureStore.getItemAsync(props.item.id.toString());
  if (amount) {
    setAmount(parseInt(amount));
  }
}
getAmount();

or, probably even better:

const getAmount = async () => {
  const storeAmount = await SecureStore.getItemAsync(props.item.id.toString());

  if (amount !== parseInt(storeAmount)) {
    setAmount(parseInt(storeAmount));
  }
}
useEffect(() => {
    getAmount();
}, [props.item.id]);

otherwise, every time it renders you'll call setAmount which will trigger a rerender

  • Related