Динамические экраны и параметры
У каждой статьи блога свой экран, но писать файл на каждую статью бессмысленно. Динамический маршрут — один файл с параметром в квадратных скобках, например [id].tsx. Значение параметра берётся из адреса: /posts/7 откроет этот экран с id, равным 7.
Данные для примера
Пока статьи лежат в обычном массиве — в следующей главе их заменит загрузка из API. Создайте папку data и файл:
// data/posts.ts
export type Post = { id: number; title: string; body: string };
export const posts: Post[] = [
{ id: 1, title: 'Первая статья', body: 'Текст первой статьи.' },
{ id: 2, title: 'Вторая статья', body: 'Текст второй статьи.' },
{ id: 3, title: 'Третья статья', body: 'Текст третьей статьи.' },
];Экран статьи
Создайте папку app/posts и в ней файл [id].tsx — квадратные скобки входят в имя файла:
// app/posts/[id].tsx
import { Stack, useLocalSearchParams } from 'expo-router';
import { Text, View } from 'react-native';
import { posts } from '@/data/posts';
export default function PostScreen() {
const { id } = useLocalSearchParams<{ id: string }>();
const post = posts.find((p) => p.id === Number(id));
if (!post) {
return <Text>Статья не найдена</Text>;
}
return (
<View style={{ flex: 1, padding: 16, gap: 12 }}>
<Stack.Screen options={{ title: post.title }} />
<Text style={{ fontSize: 22, fontWeight: 'bold' }}>{post.title}</Text>
<Text style={{ fontSize: 16 }}>{post.body}</Text>
</View>
);
}useLocalSearchParams возвращает параметры текущего экрана. Значения всегда строки, поэтому id переводится в число перед сравнением.
Ссылки на статьи
На главном экране выведите список статей со ссылками:
// app/index.tsx
import { Link } from 'expo-router';
import { FlatList, Text } from 'react-native';
import { posts } from '@/data/posts';
export default function Index() {
return (
<FlatList
data={posts}
keyExtractor={(item) => String(item.id)}
renderItem={({ item }) => (
<Link
href={{ pathname: '/posts/[id]', params: { id: item.id } }}
style={{ padding: 16, fontSize: 18 }}
>
{item.title}
</Link>
)}
/>
);
}Нажмите на «Вторая статья» — откроется её экран с заголовком в шапке. Объект href с pathname и params удобнее, чем склеивать строку; строка вида '/posts/' + item.id тоже работает.
Параметры из кода
С useRouter параметры передаются так же:
// app/index.tsx
router.push({ pathname: '/posts/[id]', params: { id: 2 } });Дополнительные параметры, которых нет в имени файла, попадают в адрес как строка запроса: params: { id: 2, from: 'home' } даст /posts/2?from=home, и useLocalSearchParams вернёт оба.
Частая ошибка
Сравнивать параметр с числом без преобразования: posts.find((p) => p.id === id). Параметр — строка '2', а p.id — число 2, строгое сравнение всегда ложно, и экран покажет «Статья не найдена». Преобразуйте значение: Number(id).