Encodera

Спасибо, что читаете!

Пожертвуйте сайту, мы стараемся ради вас.

Оглавление

Динамические экраны и параметры

У каждой статьи блога свой экран, но писать файл на каждую статью бессмысленно. Динамический маршрут — один файл с параметром в квадратных скобках, например [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).

Спасибо, что читаете!

Пожертвуйте сайту, мы стараемся ради вас.