Как сохранить элементы с помощью AsyncStorage на одном экране, а затем отобразить их на другом экране

#javascript #reactjs #react-redux #react-native-android #asyncstorage

Вопрос:

Первый экран предназначен для отображения истории сохраненных элементов со второго экрана.

Второй экран-это сканер QR-кода. После сканирования QR — кода отображается модальный код с информацией, полученной из QR-кода. В нем также есть кнопка для сохранения информации. Сохраненная информация извлекается на первом экране в плоский список.

Проблема, с которой я столкнулся, заключается в том, что сохраненная информация не отображается на первом экране. Я получаю это только в консоли.log [Error: [AsyncStorage] Passing null/undefined as value is not supported. If you want to remove value, Use .remove method instead. Passed value: undefined Passed key: @QR

ПРАВКА: Я забыл написать, что ключ AsyncStorage экспортируется в верхней части файла, поэтому его можно импортировать на ПЕРВОМ ЭКРАНЕ.

КОД: ВТОРОЙ ЭКРАН, НА КОТОРОМ Я СОХРАНЯЮ ИНФОРМАЦИЮ.

 const [Link, setLink] = useState([]);

const onSuccess = e => {
    setModalVisible(true);
    console.log(e);
    const QRSave = setLink(e);
    storeQRCode(QRSave);
  };

const storeQRCode = QRSave => {
    const stringifiedQR = JSON.stringify(QRSave);

    AsyncStorage.setItem(asyncStorage, stringifiedQR).catch(err => {
      console.log(err);
    });
  };

<Button
   title="Save QR"
   onPress={() => {
   scanner.reactivate();
   storeQRCode();
   showToast();
 }}
/>
 

КОД: ПЕРВЫЙ ЭКРАН, НА КОТОРОМ ОТОБРАЖАЕТСЯ ИСТОРИЯ СОХРАНЕННОЙ ИНФОРМАЦИИ.

 const [Data, setData] = useState({});

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

  const restoreQRCode = () => {
    AsyncStorage.getItem(asyncStorage)
      .then(stringifiedQR => {
        const parsedQR = JSON.parse(stringifiedQR);
        console.log(stringifiedQR);
        if (!parsedQR || typeof parsedQR !== 'object') return;

        setData(parsedQR);
      })
      .catch(err => {
        console.log(err);
      });
  };

<FlatList
  data={Data}
  keyExtractor={(_, index) => index.toString()}
  renderItem={renderItem}
 />
 

Комментарии:

1. вы использовали react-навигацию v5?

2. @NaldDev Да, я использую навигацию React V5. Если этот вариант выше сделать невозможно. Я должен передать сохраненную информацию через навигацию React. Вроде как хотите избежать этого, так как отправлять данные можно только с помощью навигации React, когда вы переходите только на этот конкретный экран??????

Ответ №1:

У меня есть альтернативное решение без передачи сохраненной информации на предыдущий экран

существует событие навигации прослушивателя фокуса, код выглядит следующим образом

 useEffect(() => {
  const unsubscribe = navigation.addListener('focus', () => {
    // do something when this screen back to focus for example you can load data again whenever that screen focus...

    console.log('Screen X is focus again')
    loadData()
  })

  return unsubscribe
}, [navigation])
 

Вы можете прочитать больше об этих событиях навигации по этой ссылке

Комментарии:

1. Хм, не знаю, что с этим делать. Я раньше не использовал события навигации react. Когда у меня будет время, я смогу разобраться в этом.

2. Я запустил это, и на нем отображается сохраненный элемент. Я столкнулся с одной проблемой, и это так. На нем показан только один предмет. Если я сохраню еще один предмет. Он заменяет сохраненный в данный момент элемент и не добавляет второй элемент в список.

Ответ №2:

Вам нужен поставщик контекста, окружающий оба экрана, тогда у вас будет доступ к данным в обоих.

Что-то вроде:

 //QrCodeContext.js
export const QrCodeContext = createContext();

const KEY = "QR";
export const QrCodeProvider = ({ children }) => {
    const [loading, setLoading] = useState(true);
    const [qrCode, setQrCode] = useState({});

    //This effect hook runs on mount and loads your QR code, if it exists.
    useEffect(() => {
        const loadQrCode = async () => {
            const code = await loadItemFromAsyncStorage(KEY, {});
            setQrCode(() => code);
            setLoading(() => false);
        };
        loadQrCode();

    }, [])

    //This effect hook runs every time the code changes and persists it to async storage
    useEffect(() => {
        const storeQrCode = async (value) => {
            await storeItemInAsyncStorage(KEY, value);
        }

        storeQrCode(qrCode);

        return () => {
            storeQrCode(qrCode);
        } // this means the code will always be saved when the component unmounts.

    }, [qrCode]);

    //These three properties are available to your child components.
    const propertiesExposedToConsumers = { setQrCode, qrCode, loading };

    return (<QrCodeContext.Provider value={propertiesExposedToConsumers}>
        {children}
    </QrCodeContext.Provider>
    );
}



//asyncStrageWrapper.js.

export const storeItemInAsyncStorage = async (key, value) => {
    try {
        const jsonValue = JSON.stringify(value);
        await AsyncStorage.setItem(key, jsonValue);
    } catch (e) {
        console.log(e);
    }
};

export const loadItemFromAsyncStorage = async (key, defaultValue = undefined) => {
    try {
        const jsonValue = await AsyncStorage.getItem(key);
        return jsonValue != null ? JSON.parse(jsonValue) : defaultValue;
    } catch (e) {
        console.log(e);
        return defaultValue;
    }
};


//screenOne.js

const ScreenOne = () => {
    const { loading, qrCode } = useContext(QrCodeContext);

   //your render code here
}

//screenTwo.js
const ScreenTwo = () => {
    const { loading, setQrCode } = useContext(QrCodeContext);
    //your scanner code here.
}

//App.js
const App = () => (
    <QrCodeProvider>
       <NavigationContainer>
      <Stack.Navigator initialRouteName={"ScreenOne"}>
      <Stack.Screen name="ScreenOne" component={ScreenOne} />
        <Stack.Screen name="ScreenTwo" component={ScreenTwo} />
      </Stack.Navigator>
    </NavigationContainer>
    </QrCodeProvider >
)
 

Комментарии:

1. У меня сейчас действительно нет времени разбираться в этом. Но я дам тебе награду, так как она истекает завтра