#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. У меня сейчас действительно нет времени разбираться в этом. Но я дам тебе награду, так как она истекает завтра