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

Передача параметров в маршруты

Помните, я сказал "подробнее об этом позже, когда мы поговорим о параметрах!"? Что ж, время пришло.

Теперь, когда мы знаем, как создать стековый навигатор с некоторыми маршрутами и перемещаться между этими маршрутами, давайте рассмотрим, как можно передавать данные маршрутам при переходе к ним.

Здесь есть две составляющие:

  1. Передать параметры маршруту, поместив их в объект в качестве второго параметра функции navigation.navigate: navigation.navigate('RouteName', { /* params go here */ }).

  2. Прочитайте параметры в компоненте экрана: route.params.

Мы рекомендуем передавать параметры в JSON-сериализуемом виде. Таким образом, вы сможете использовать state persistence, а ваши экранные компоненты будут иметь правильный контракт для реализации deep linking.

 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
function HomeScreen({ navigation }) {
    return (
        <View
            style={{
                flex: 1,
                alignItems: 'center',
                justifyContent: 'center',
            }}
        >
            <Text>Home Screen</Text>
            <Button
                title="Go to Details"
                onPress={() => {
                    /* 1. Navigate to the Details route with params */
                    navigation.navigate('Details', {
                        itemId: 86,
                        otherParam:
                            'anything you want here',
                    });
                }}
            />
        </View>
    );
}

function DetailsScreen({ route, navigation }) {
    /* 2. Get the param */
    const { itemId, otherParam } = route.params;
    return (
        <View
            style={{
                flex: 1,
                alignItems: 'center',
                justifyContent: 'center',
            }}
        >
            <Text>Details Screen</Text>
            <Text>itemId: {JSON.stringify(itemId)}</Text>
            <Text>
                otherParam: {JSON.stringify(otherParam)}
            </Text>
            <Button
                title="Go to Details... again"
                onPress={() =>
                    navigation.push('Details', {
                        itemId: Math.floor(
                            Math.random() * 100
                        ),
                    })
                }
            />
            <Button
                title="Go to Home"
                onPress={() => navigation.navigate('Home')}
            />
            <Button
                title="Go back"
                onPress={() => navigation.goBack()}
            />
        </View>
    );
}

Screen with passed parameters

Начальные параметры

Вы можете передать экрану некоторые начальные параметры. Если при переходе к этому экрану не было задано никаких параметров, то будут использованы начальные параметры. Они также неглубоко объединяются с любыми передаваемыми параметрами. Начальные параметры могут быть заданы с помощью свойства initialParams:

1
2
3
4
5
<Stack.Screen
    name="Details"
    component={DetailsScreen}
    initialParams={{ itemId: 42 }}
/>

Обновление параметров

Экраны также могут обновлять свои параметры, как и обновлять свое состояние. Метод navigation.setParams позволяет обновить параметры экрана. Подробнее об этом см. в API reference for setParams.

Основные варианты использования:

1
2
3
navigation.setParams({
    query: 'someText',
});

Примечание: Избегайте использования setParams для обновления параметров экрана, таких как title и т.д. Если вам нужно обновить параметры, используйте вместо этого setOptions.

Передача параметров в предыдущий экран

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

Для этого можно использовать метод navigate, который действует как goBack, если экран уже существует. Для передачи данных обратно в navigate можно передать params:

 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
function HomeScreen({ navigation, route }) {
    React.useEffect(() => {
        if (route.params?.post) {
            // Post updated, do something with `route.params.post`
            // For example, send the post to the server
        }
    }, [route.params?.post]);

    return (
        <View
            style={{
                flex: 1,
                alignItems: 'center',
                justifyContent: 'center',
            }}
        >
            <Button
                title="Create post"
                onPress={() =>
                    navigation.navigate('CreatePost')
                }
            />
            <Text style={{ margin: 10 }}>
                Post: {route.params?.post}
            </Text>
        </View>
    );
}

function CreatePostScreen({ navigation, route }) {
    const [postText, setPostText] = React.useState('');

    return (
        <>
            <TextInput
                multiline
                placeholder="What's on your mind?"
                style={{
                    height: 200,
                    padding: 10,
                    backgroundColor: 'white',
                }}
                value={postText}
                onChangeText={setPostText}
            />
            <Button
                title="Done"
                onPress={() => {
                    // Pass and merge params back to home screen
                    navigation.navigate({
                        name: 'Home',
                        params: { post: postText },
                        merge: true,
                    });
                }}
            />
        </>
    );
}

Здесь после нажатия кнопки "Готово" на главном экране в файле route.params будет обновлен текст сообщения, переданный в navigate.

Передача параметров во вложенные навигаторы

Если у вас есть вложенные навигаторы, то передавать параметры нужно немного по-другому. Например, у вас есть навигатор внутри экрана Account, и вы хотите передать параметры экрану Settings внутри этого навигатора. Тогда можно передать параметры следующим образом:

1
2
3
4
navigation.navigate('Account', {
    screen: 'Settings',
    params: { user: 'jane' },
});

Подробнее о вложении навигаторов см. в Nesting navigators.

Что должно быть в параметрах

Важно понимать, какого рода данные должны быть в params. Params - это как опции для экрана. Они должны содержать только информацию для настройки того, что будет отображаться на экране. Избегайте передачи полных данных, которые будут отображаться на самом экране (например, вместо объекта user передавайте id пользователя). Также не следует передавать данные, которые используются несколькими экранами, такие данные должны находиться в глобальном хранилище.

Объект route можно также представить как URL. Если бы у вашего экрана был URL, что должно быть в нем? Параметры не должны содержать данные, которые, по вашему мнению, не должны быть в URL. Часто это означает, что следует хранить как можно меньше данных, необходимых для определения того, что представляет собой экран. Вспомните посещение торгового сайта, когда вы видите списки товаров, URL обычно содержит название категории, тип сортировки, любые фильтры и т.д., но не содержит фактического списка товаров, отображаемого на экране.

Например, если у вас есть экран Профиль. При переходе к нему у вас может возникнуть соблазн передать в params объект пользователя:

1
2
3
4
5
6
7
8
9
// Don't do this
navigation.navigate('Profile', {
    user: {
        id: 'jane',
        firstName: 'Jane',
        lastName: 'Done',
        age: 25,
    },
});

Это выглядит удобно и позволяет без лишней работы обращаться к объектам пользователей с помощью route.params.user.

Однако это антипаттерн. Такие данные, как пользовательские объекты, должны находиться в глобальном хранилище, а не в состоянии навигации. В противном случае одни и те же данные будут дублироваться в нескольких местах. Это может привести к ошибкам, например, к тому, что на экране профиля будут отображаться устаревшие данные, даже если объект пользователя изменился после навигации.

Кроме того, становится проблематично создавать ссылки на экран с помощью глубокой привязки или в Интернете, поскольку:

  1. URL является представлением экрана, поэтому он также должен содержать параметры, т.е. полный объект пользователя, что может сделать URL очень длинным и нечитаемым
  2. Поскольку объект пользователя находится в URL, можно передать случайный объект пользователя, представляющий несуществующего пользователя или имеющий неверные данные в профиле
  3. Если объект пользователя не передан или неправильно отформатирован, это может привести к сбоям, так как экран не будет знать, как его обработать.

Более эффективным способом является передача в params только идентификатора пользователя:

1
navigation.navigate('Profile', { userId: 'jane' });

Теперь вы можете использовать переданный userId для получения пользователя из вашего глобального хранилища. Это устраняет множество проблем, таких как устаревшие данные или проблемные URL.

В качестве примеров того, что должно содержаться в параметрах, можно привести следующие:

  1. Идентификаторы, такие как идентификатор пользователя, идентификатор элемента и т.д., например, navigation.navigate('Profile', { userId: 'Jane' }).
  2. Параметры для сортировки, фильтрации данных и т.д., когда у вас есть список элементов, например, navigation.navigate('Feeds', { sortBy: 'latest' }).
  3. Временные метки, номера страниц или курсоры для пагинации, например navigation.navigate('Chat', { beforeTime: 1603897152675 }).
  4. Данные для заполнения входов на экране для составления сообщения, например navigation.navigate('ComposeTweet', { title: 'Hello world!' }).

По сути, в params следует передавать наименьшее количество данных, необходимых для идентификации экрана. Для многих случаев это означает передачу идентификатора объекта вместо передачи полного объекта. Храните данные приложения отдельно от состояния навигации.

Резюме

  • navigate и push принимают необязательный второй аргумент, позволяющий передавать параметры маршрута, по которому осуществляется навигация. Например: navigation.navigate('RouteName', { paramName: 'value' }).
  • Вы можете читать параметры через route.params внутри экрана.
  • Обновить параметры экрана можно с помощью команды navigation.setParams.
  • Начальные параметры могут быть переданы через параметр initialParams на Screen.
  • Параметры должны содержать минимальные данные, необходимые для отображения экрана, не более того

Ссылки

Комментарии