Перейти к содержанию

Сохранение состояния

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

Это особенно важно при разработке, поскольку позволяет разработчику оставаться на том же экране при обновлении приложения.

Использование

Для сохранения состояния navigation state мы можем использовать реквизиты onStateChange и initialState контейнера.

  • onStateChange - этот реквизит уведомляет нас о любых изменениях состояния. Мы можем сохранять состояние в этом обратном вызове.
  • initialState - Этот реквизит позволяет нам передать начальное состояние для использования в navigation state. Мы можем передать восстановленное состояние в этом реквизите.
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
import * as React from 'react';
import { Linking, Platform } from 'react-native';
import AsyncStorage from '@react-native-async-storage/async-storage';
import { NavigationContainer } from '@react-navigation/native';

const PERSISTENCE_KEY = 'NAVIGATION_STATE_V1';

export default function App() {
    const [isReady, setIsReady] = React.useState(false);
    const [
        initialState,
        setInitialState,
    ] = React.useState();

    React.useEffect(() => {
        const restoreState = async () => {
            try {
                const initialUrl = await Linking.getInitialURL();

                if (
                    Platform.OS !== 'web' &&
                    initialUrl == null
                ) {
                    // Only restore state if there's no deep link and we're not on web
                    const savedStateString = await AsyncStorage.getItem(
                        PERSISTENCE_KEY
                    );
                    const state = savedStateString
                        ? JSON.parse(savedStateString)
                        : undefined;

                    if (state !== undefined) {
                        setInitialState(state);
                    }
                }
            } finally {
                setIsReady(true);
            }
        };

        if (!isReady) {
            restoreState();
        }
    }, [isReady]);

    if (!isReady) {
        return null;
    }

    return (
        <NavigationContainer
            initialState={initialState}
            onStateChange={(state) =>
                AsyncStorage.setItem(
                    PERSISTENCE_KEY,
                    JSON.stringify(state)
                )
            }
        >
            {/* ... */}
        </NavigationContainer>
    );
}

Режим разработки

Эта функция особенно полезна в режиме разработки. Вы можете включить ее выборочно, используя следующий подход:

1
2
3
const [isReady, setIsReady] = React.useState(
    __DEV__ ? false : true
);

Хотя его можно использовать и в производстве, следует соблюдать осторожность, поскольку он может сделать приложение непригодным для использования, если оно аварийно завершает работу на определенном экране - ведь после перезапуска пользователь все равно будет находиться на том же экране.

Loading View

Поскольку состояние восстанавливается асинхронно, приложение должно отобразить пустой/загрузочный вид на некоторое время, прежде чем мы получим начальное состояние. Чтобы справиться с этим, мы можем возвращать загрузочное представление, когда isReady равно false:

1
2
3
if (!isReady) {
    return <ActivityIndicator />;
}

Предупреждение: Сериализуемое состояние

Для работы этой функции состояние каждого параметра, маршрута и навигации должно быть полностью сериализуемым. Обычно состояние сериализуется в виде JSON-строки. Это означает, что маршруты и параметры не должны содержать функций, экземпляров классов или рекурсивных структур данных. React Navigation уже предупреждает вас во время разработки, если встречает несериализуемые данные, поэтому обратите внимание на это предупреждение, если вы планируете сохранять состояние навигации.

Вы можете изменить объект начального состояния перед передачей его контейнеру, но учтите, что если ваш initialState не является действительным состоянием навигации, то React Navigation может не справиться с ситуацией изящно.

Ссылки

Комментарии