0Pricing
React Native Academy · Урок

Создание простой карточки профиля

Объедините View, Text и Image, чтобы создать компонент карточки профиля с аватаром, именем и описанием, закрепив навыки композиции компонентов.

«Создание простой карточки профиля» — бесплатный урок React Native Academy на CoddyKit. Это урок 4 из 4. Ты можешь прочитать весь урок бесплатно ниже — а потом практиковать его прямо в браузере с встроенным редактором кода и ИИ-репетитором 24/7. Это часть пути обучения React Native Academy, и твой прогресс синхронизируется между веб-версией и приложением CoddyKit. Курс React Native Academy содержит 4 уроков всего.

Части этого урока еще не переведены и отображаются на английском.

Component Composition in React Native

Composition means building big UI from small pieces. A profile card mixes a View, an Image, and Text — and once built, you can reuse it for every user.

// The goal: a reusable ProfileCard component
// that accepts props and renders a complete card UI

// Usage:
<ProfileCard
  name='Alice Johnson'
  role='Senior Developer'
  bio='Building great mobile apps with React Native.'
  avatarUri='https://i.pravatar.cc/150?img=1'
  followers={1240}
/>

Planning the Card Layout

Before coding, plan the card: avatar, name, role, bio, maybe a stats row. A column for the overall layout, a row for side-by-side bits. A quick sketch saves time.

// Conceptual structure (pseudo-code)
<View card>
  <Image avatar />
  <Text name />
  <Text role />
  <Text bio />
  <View statsRow>
    <View stat><Text number/><Text label/></View>
    <View stat><Text number/><Text label/></View>
    <View stat><Text number/><Text label/></View>
  </View>
</View>

Building the Card Container

Start with the card container View. Add borderRadius for rounded corners, a shadow for lift, and padding inside. Center the children with alignItems.

import { View, StyleSheet } from 'react-native';

export default function ProfileCard({ children }) {
  return (
    <View style={styles.card}>
      {children}
    </View>
  );
}

const styles = StyleSheet.create({
  card: {
    backgroundColor: '#fff',
    borderRadius: 20,
    padding: 24,
    marginHorizontal: 20,
    marginVertical: 12,
    alignItems: 'center',
    shadowColor: '#000',
    shadowOffset: { width: 0, height: 4 },
    shadowOpacity: 0.1,
    shadowRadius: 12,
    elevation: 5,
  },
});

Adding the Avatar Image

Add the avatar at the top: a square View with borderRadius half its size and overflow: hidden makes it a circle. Take the image as a prop to stay reusable.

import { Image, View, StyleSheet } from 'react-native';

function Avatar({ uri, size = 90 }) {
  const radius = size / 2;
  return (
    <View style={[
      styles.ring,
      { width: size + 6, height: size + 6, borderRadius: radius + 3 }
    ]}>
      <View style={[
        styles.clip,
        { width: size, height: size, borderRadius: radius }
      ]}>
        <Image source={{ uri }} style={{ width: size, height: size }} />
      </View>
    </View>
  );
}

const styles = StyleSheet.create({
  ring: { borderWidth: 3, borderColor: '#4f86f7', alignItems: 'center', justifyContent: 'center' },
  clip: { overflow: 'hidden', backgroundColor: '#e0e0e0' },
});

Name, Role, and Bio Text

Below the avatar, add three Text blocks: a big bold name, a smaller muted role, and a centered bio. A little marginTop between them sets a clean rhythm.

import { Text, StyleSheet } from 'react-native';

function CardInfo({ name, role, bio }) {
  return (
    <>
      <Text style={styles.name}>{name}</Text>
      <Text style={styles.role}>{role}</Text>
      <Text style={styles.bio} numberOfLines={3}>{bio}</Text>
    </>
  );
}

const styles = StyleSheet.create({
  name: { fontSize: 22, fontWeight: '700', color: '#111', marginTop: 14, textAlign: 'center' },
  role: { fontSize: 14, color: '#4f86f7', fontWeight: '500', marginTop: 4, textAlign: 'center' },
  bio: { fontSize: 14, color: '#666', lineHeight: 22, marginTop: 10, textAlign: 'center' },
});

Stat Counter Row

Many cards end with a stats row: followers and posts side by side. Use flexDirection: row with justifyContent: space-around and a top border to set it off.

import { View, Text, StyleSheet } from 'react-native';

function StatRow({ followers, following, posts }) {
  return (
    <View style={styles.row}>
      <Stat value={posts} label='Posts' />
      <Stat value={followers} label='Followers' />
      <Stat value={following} label='Following' />
    </View>
  );
}

function Stat({ value, label }) {
  return (
    <View style={styles.stat}>
      <Text style={styles.value}>{value}</Text>
      <Text style={styles.label}>{label}</Text>
    </View>
  );
}

const styles = StyleSheet.create({
  row: { flexDirection: 'row', justifyContent: 'space-around', width: '100%', borderTopWidth: 1, borderTopColor: '#eee', marginTop: 20, paddingTop: 16 },
  stat: { alignItems: 'center' },
  value: { fontSize: 18, fontWeight: '700', color: '#111' },
  label: { fontSize: 12, color: '#999', marginTop: 2 },
});

Assembling the Full ProfileCard

Now combine the parts into one ProfileCard that takes props and just renders them. No internal state — pure presentation makes it easy to reuse and test.

import { View, StyleSheet } from 'react-native';
import Avatar from './Avatar';
import CardInfo from './CardInfo';
import StatRow from './StatRow';

export default function ProfileCard({
  name, role, bio, avatarUri, followers, following, posts
}) {
  return (
    <View style={styles.card}>
      <Avatar uri={avatarUri} size={90} />
      <CardInfo name={name} role={role} bio={bio} />
      <StatRow followers={followers} following={following} posts={posts} />
    </View>
  );
}

const styles = StyleSheet.create({
  card: {
    backgroundColor: '#fff',
    borderRadius: 20,
    padding: 24,
    marginHorizontal: 20,
    alignItems: 'center',
    elevation: 5,
    shadowColor: '#000',
    shadowOffset: { width: 0, height: 4 },
    shadowOpacity: 0.1,
    shadowRadius: 12,
  },
});

Rendering Multiple Cards in a List

To show many cards, map over an array of users. For long lists reach for FlatList; for a few, ScrollView is fine. Give each card a unique key.

import { ScrollView } from 'react-native';
import ProfileCard from './ProfileCard';

const users = [
  { id: '1', name: 'Alice', role: 'Designer', bio: 'Crafting beautiful UIs.', avatarUri: 'https://i.pravatar.cc/150?img=1', followers: 980, following: 210, posts: 45 },
  { id: '2', name: 'Bob', role: 'Developer', bio: 'Loves React Native and coffee.', avatarUri: 'https://i.pravatar.cc/150?img=2', followers: 1420, following: 380, posts: 73 },
];

export default function App() {
  return (
    <ScrollView style={{ backgroundColor: '#f5f5f5' }}>
      {users.map(user => (
        <ProfileCard key={user.id} {...user} />
      ))}
    </ScrollView>
  );
}

Adding a Follow Button

Make it interactive with a Follow button using TouchableOpacity. Toggle the label and color, but keep the real API call in the parent via a callback.

import { TouchableOpacity, Text, StyleSheet } from 'react-native';
import { useState } from 'react';

export default function FollowButton({ onPress }) {
  const [following, setFollowing] = useState(false);

  function handlePress() {
    setFollowing(prev => !prev);
    onPress && onPress(!following);
  }

  return (
    <TouchableOpacity
      style={[styles.btn, following && styles.btnActive]}
      onPress={handlePress}
    >
      <Text style={[styles.label, following && styles.labelActive]}>
        {following ? 'Following' : 'Follow'}
      </Text>
    </TouchableOpacity>
  );
}

const styles = StyleSheet.create({
  btn: { borderWidth: 1.5, borderColor: '#4f86f7', borderRadius: 20, paddingHorizontal: 24, paddingVertical: 8, marginTop: 16 },
  btnActive: { backgroundColor: '#4f86f7' },
  label: { color: '#4f86f7', fontWeight: '600' },
  labelActive: { color: '#fff' },
});

Adding Accessibility to the Card

Make the card accessible: set accessible on the outer View with a label that sums it up, so screen readers announce the whole card as one clear unit.

import { View, Text, StyleSheet } from 'react-native';

export default function AccessibleProfileCard({ name, role, followers }) {
  const label = `${name}, ${role}, ${followers} followers`;

  return (
    <View
      style={styles.card}
      accessible
      accessibilityLabel={label}
      accessibilityRole='summary'
    >
      <Text style={styles.name}>{name}</Text>
      <Text style={styles.role}>{role}</Text>
      <Text style={styles.followers}>{followers} followers</Text>
    </View>
  );
}

const styles = StyleSheet.create({
  card: { padding: 16, borderRadius: 12, backgroundColor: '#fff', elevation: 3 },
  name: { fontSize: 20, fontWeight: 'bold' },
  role: { color: '#666', marginTop: 4 },
  followers: { color: '#4f86f7', marginTop: 8 },
});

Skeleton Loading State

While data loads, show a skeleton — grey pulsing boxes shaped like the card. It feels more polished than a spinner and hints at what is coming.

import { View, StyleSheet } from 'react-native';

export default function ProfileCardSkeleton() {
  return (
    <View style={styles.card}>
      {/* Avatar placeholder */}
      <View style={styles.avatarSkeleton} />
      {/* Name placeholder */}
      <View style={styles.nameSkeleton} />
      {/* Role placeholder */}
      <View style={styles.roleSkeleton} />
      {/* Bio placeholder lines */}
      <View style={[styles.bioSkeleton, { width: '100%' }]} />
      <View style={[styles.bioSkeleton, { width: '80%' }]} />
    </View>
  );
}

const styles = StyleSheet.create({
  card: { padding: 24, borderRadius: 20, backgroundColor: '#fff', alignItems: 'center', margin: 16, elevation: 3 },
  avatarSkeleton: { width: 90, height: 90, borderRadius: 45, backgroundColor: '#e0e0e0' },
  nameSkeleton: { width: 140, height: 22, borderRadius: 4, backgroundColor: '#e0e0e0', marginTop: 14 },
  roleSkeleton: { width: 100, height: 16, borderRadius: 4, backgroundColor: '#e0e0e0', marginTop: 8 },
  bioSkeleton: { height: 14, borderRadius: 4, backgroundColor: '#e0e0e0', marginTop: 8 },
});

Quick Check

Quick check! See how your ProfileCard skills stack up. 🎉

Lesson Recap

Awesome — you composed a real card! You combined View, Text, and Image, used props to reuse it, and added skeletons for polish. Next up: StyleSheet and Flexbox.

Часто задаваемые вопросы

Урок «Создание простой карточки профиля» бесплатный?

Да — полный текст урока «Создание простой карточки профиля» бесплатно доступен здесь в веб-версии. Чтобы практиковать его интерактивно (встроенный редактор кода и ИИ-репетитор 24/7) и разблокировать остальной курс React Native Academy, подпишись на CoddyKit PRO. Курс React Native Academy содержит 4 уроков всего.

Чему я научусь в уроке «Создание простой карточки профиля»?

Объедините View, Text и Image, чтобы создать компонент карточки профиля с аватаром, именем и описанием, закрепив навыки композиции компонентов. Ты практикуешь React Native Academy с помощью реального кода, который запускаешь прямо в браузере, и ИИ-репетитор 24/7 отвечает на твои вопросы во время урока.

Нужен ли мне опыт, чтобы начать React Native Academy?

Предыдущий опыт не требуется. React Native Academy на CoddyKit структурирован для всех уровней — от новичков до продвинутых, поэтому ты можешь начать отсюда или с самого начала и учиться в своем темпе. Это урок 4 из 4.

Сколько времени занимает урок «Создание простой карточки профиля»?

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

Можно ли писать и запускать код в этом уроке React Native Academy?

Да. Каждый урок React Native Academy включает встроенный редактор кода, поэтому ты пишешь и запускаешь реальный код прямо в браузере и получаешь моментальную обратную связь от AI — локальная установка не требуется.

Все уроки этого курса

  1. Компонент View как контейнер
  2. Отображение текста и настройка шрифтов
  3. Отображение изображений из локальных и удалённых источников
  4. Создание простой карточки профиля
← Назад к React Native Academy