Как запустить условный рендеринг со значением из AsyncStorage в React Native?

#react-native

Вопрос:

Я использую React Native для создания приложения и борюсь с условным рендерингом. Я хочу, чтобы экран учебника отображался только при первом открытии приложения пользователем. После этого его больше не следует показывать. В учебнике есть кнопка «Начать», которая должна вызвать переход к приложению. Нажатие кнопки сохраняет в AsyncStorage значение «showTutorial» в значение false, поэтому в следующий раз оно не будет отображаться. Однако нажатие кнопки не скрывает учебник и не переходит в главное приложение, только если я снова открою приложение, сохраню файл (работающий в VSCode) или перезагрузлю приложение, затем оно обновится, и страница учебника больше не отображается. Я не понимаю, почему это не работает, в частности, почему переменная состояния не изменяется и не запускает другой экран.

Локальное хранилище обновляется при нажатии кнопки с правильным значением на основе журналов.

Итак, как я могу перейти к основному приложению непосредственно после нажатия кнопки?

app-navigation.js:

 const [showTutorial, setShowTutorial] = React.useState(true);

const getShowTutorial = async () => {
    try {
        const LS_showTutorial = await AsyncStorage.getItem('showTutorial');
        if (LS_showTutorial !== null) {
            setShowTutorial(JSON.parse(LS_showTutorial));
        }
    } catch (error) {
        console.log('Failed to fetch the data from storage', error);
    }
};

React.useEffect(() => {
    getShowTutorial();
}, []);

return (
    <View style={{ flex: 1 }}>
        { showTutorial ? ( // THIS DOES NOT CHANGE WHEN PRESSING THE BUTTON
            <TutorialScreen/>
        ) : (
            <DashboardScreen/>
        )}
    </View>
);
 

tutorial.js

 const saveData = async (key, value) => {
    try {
        console.log('Saving local data with ', key, ' and ', JSON.stringify(value));
        await AsyncStorage.setItem(key, JSON.stringify(value));
    } catch (error) {
        console.log('Something went wrong', error);
    }
};

return (
    <View style={styles.basicContainer}>
        <Text style={styles.textTitle}>
            Hello world!
        </Text>
        <Button
            onPress={() => {
                saveData('showTutorial', false);
            }}
        >Get started</Button>
    </View>
);
 

P.S. Протестировано только на эмуляторе Android и физическом устройстве.

Ответ №1:

Проблема, которую я вижу, заключается в том, что вы не используете асинхронное/ожидание для вызова getShowTutorial в useEffect . В результате компонент в app-navigation.js визуализируется до AsyncStorage того, как можно будет получить значение in. В этой статье объясняется идея, лежащая в основе ожидания асинхронного кода useEffect . https://javascript.plainenglish.io/how-to-use-async-function-in-react-hook-useeffect-typescript-js-6204a788a435

Попробуйте что-нибудь вроде этого:

 useEffect(() => {
  (
    async function () {
      await getShowTutorial()
    }
  )()
}, [])
 

Кроме того, попробуйте использовать ожидание/асинхронность с onPress обработчиком:

 onPress={async () => {await saveData('showTutorial', false)}}
 

Дайте мне знать, если это поможет!

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

1. Я попробовал ваши предложения и не помог. Он работает так же, как и раньше.

2. По этой части: if (LS_showTutorial !== null) { setShowTutorial(JSON.parse(LS_showTutorial)); } делает JSON.parse(LS_showTutorial) === false и не "false" делает ? Если вы устанавливаете это в строку, она будет оцениваться как правдивая, что объясняет, почему она не работает

3. JSON.parse возвращает логическое false значение из строки "false" . Я дважды проверил, и это действительно false как логическое setShowTutorial(JSON.parse(LS_showTutorial)) значение . Проблема не в самой функции, если я перезагружаю приложение или сохраняю файл, эта функция запускается правильно, и страница учебника исчезает. Однако он не входит в функцию, когда я нажимаю кнопку.