0Pricing
React Native Academy · บทเรียน

การประกอบการ์ดโปรไฟล์อย่างง่าย

ผสาน View, Text และ Image เพื่อสร้างคอมโพเนนต์การ์ดโปรไฟล์ที่แสดงรูปประจำตัว ชื่อ และประวัติย่อ พร้อมเสริมทักษะการประกอบคอมโพเนนต์

การประกอบการ์ดโปรไฟล์อย่างง่าย เป็นบทเรียน React Native Academy ฟรีบน CoddyKit นี่คือบทเรียนที่ 4 จากทั้งหมด 4 บทเรียน คุณสามารถอ่านบทเรียนทั้งหมดด้านล่างฟรี — จากนั้นลองปฏิบัติด้วยตัวคุณเองในเบราว์เซอร์พร้อมตัวแก้ไขโค้ดในตัวและติวเตอร์ AI ตลอด 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.

คำถามที่พบบ่อย

บทเรียน “การประกอบการ์ดโปรไฟล์อย่างง่าย” ฟรีหรือไม่

ใช่ — ข้อความเต็มของ “การประกอบการ์ดโปรไฟล์อย่างง่าย” ฟรีให้อ่านที่นี่บนเว็บ เพื่อปฏิบัติแบบโต้ตอบ (ตัวแก้ไขโค้ดในตัวและติวเตอร์ AI ตลอด 24/7) และปลดล็อคส่วนที่เหลือของคอร์ส React Native Academy ให้อัปเกรดเป็น CoddyKit PRO คอร์ส React Native Academy มีบทเรียนทั้งหมด 4 บทเรียน

คุณจะเรียนรู้อะไรในบทเรียน “การประกอบการ์ดโปรไฟล์อย่างง่าย”

ผสาน View, Text และ Image เพื่อสร้างคอมโพเนนต์การ์ดโปรไฟล์ที่แสดงรูปประจำตัว ชื่อ และประวัติย่อ พร้อมเสริมทักษะการประกอบคอมโพเนนต์ คุณปฏิบัติ React Native Academy ด้วยโค้ดที่ใช้งานได้จริงที่คุณเรียกใช้โดยตรงในเบราว์เซอร์ และติวเตอร์ AI ตลอด 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