Props ile Veri Aktarma
Props kabul eden yeniden kullanılabilir bir bileşen tanımlayın, değerleri üst bileşenden aktarın ve beklenen prop yapılarını belgelemek için PropTypes veya TypeScript kullanın.
Props ile Veri Aktarma, CoddyKit'te ücretsiz bir React Native Academy dersidir. Bu, 4 dersinin 1. dersidir. Aşağıdan dersin tamamını ücretsiz okuyabilir, sonra tarayıcıda yerleşik kod editörü ve 7/24 yapay zeka koçu ile uygulamalı olarak pratik yapabilirsin. Bu, React Native Academy öğrenme yolunun bir parçasıdır ve ilerlemeniz web ve CoddyKit uygulaması arasında senkronize olur. React Native Academy kursu toplamda 4 dersten oluşur.
Bu dersin bazı bölümleri henüz çevrilmemiş olup İngilizce olarak gösterilmektedir.
What Are Props?
Props (short for properties) are the mechanism React components use to receive input from their parent. A parent component renders a child component and passes data to it through attributes in JSX — just like HTML attributes, but for any JavaScript value including strings, numbers, objects, arrays, and functions. The child component receives all its props as a single object argument. Props flow in one direction: from parent down to child. A child component can never modify its own props — they are read-only.
import { Text, View } from 'react-native';
// Child component receives props
function Greeting({ name, age }) {
return (
<View>
<Text>Hello, {name}!</Text>
<Text>You are {age} years old.</Text>
</View>
);
}
// Parent passes data through props
export default function App() {
return (
<View style={{ flex: 1, padding: 24 }}>
<Greeting name='Alice' age={30} />
<Greeting name='Bob' age={25} />
</View>
);
}Destructuring Props
You can access props in two ways: as a single props object (function Card(props) { props.title }) or by destructuring directly in the function signature (function Card({ title, subtitle })). Destructuring is the preferred style because it makes the accepted props explicit and the code more concise. You can also provide default values for props in the destructuring syntax: { size = 16, color = '#333' }. This means the prop is optional and falls back to the default when not provided by the parent.
import { Text, View, StyleSheet } from 'react-native';
// Destructuring with default values
function Badge({ label, color = '#4f86f7', size = 14 }) {
return (
<View style={[styles.badge, { backgroundColor: color }]}>
<Text style={[styles.text, { fontSize: size }]}>{label}</Text>
</View>
);
}
export default function App() {
return (
<View style={{ gap: 8, padding: 16 }}>
<Badge label='New' /> {/* uses defaults */}
<Badge label='Sale' color='#e74c3c' /> {/* custom color */}
<Badge label='Pro' color='#2ecc71' size={12} />
</View>
);
}
const styles = StyleSheet.create({
badge: { paddingHorizontal: 10, paddingVertical: 4, borderRadius: 12, alignSelf: 'flex-start' },
text: { color: '#fff', fontWeight: 'bold' },
});Passing Different Prop Types
Props can carry any JavaScript value. Strings don't need curly braces (title='Hello'), but all other types do — numbers (count={5}), booleans (disabled={true} or just disabled), objects (style={{ color: 'red' }}), arrays (items={[1,2,3]}), and functions (onPress={handlePress}). Passing functions as props is how children communicate back to parents — the parent defines the function and passes it down; the child calls it when something happens. This pattern is central to React's unidirectional data flow.
import { View, Text, TouchableOpacity } from 'react-native';
// onPress is a function prop — callback from child to parent
function ConfirmButton({ label, count, disabled, onPress }) {
return (
<TouchableOpacity
onPress={onPress}
disabled={disabled}
style={{ opacity: disabled ? 0.4 : 1, backgroundColor: '#4f86f7', padding: 12, borderRadius: 8 }}
>
<Text style={{ color: '#fff', fontWeight: 'bold' }}>
{label} ({count})
</Text>
</TouchableOpacity>
);
}
export default function App() {
return (
<View style={{ padding: 24 }}>
<ConfirmButton
label='Add to Cart'
count={3}
disabled={false}
onPress={() => console.log('Added!')}
/>
</View>
);
}The children Prop
The special children prop holds whatever you put between the opening and closing tags of a component. This enables composition — you can build wrapper or container components that apply layout, styling, or behavior to any content nested inside. React Native's View, ScrollView, and TouchableOpacity all work this way. Define your own wrapper components with children to create reusable layout shells like cards, modals, and screen templates.
import { View, StyleSheet } from 'react-native';
// A Card wrapper that applies consistent styling
function Card({ children, style }) {
return (
<View style={[styles.card, style]}>
{children}
</View>
);
}
export default function App() {
return (
<View style={{ padding: 16 }}>
<Card>
{/* Any content can go inside the Card */}
<Text>Title</Text>
<Text>Subtitle</Text>
<Image source={{ uri: 'https://picsum.photos/200' }} style={{ width: 200, height: 100 }} />
</Card>
</View>
);
}
const styles = StyleSheet.create({
card: { backgroundColor: '#fff', borderRadius: 16, padding: 16, elevation: 3, marginBottom: 12 },
});Prop Spreading with the Spread Operator
Use the JavaScript spread operator to pass all properties of an object as individual props. This is convenient when you have a data object with many fields: <UserCard {...user} /> is equivalent to <UserCard id={user.id} name={user.name} avatar={user.avatar} />. The spread pattern is common when rendering items from an array with .map(). Be careful not to spread unknown props onto native components (View, Text) — they will trigger warnings or be silently ignored. Only spread props onto custom components that you control.
import { View, Text } from 'react-native';
const users = [
{ id: '1', name: 'Alice', role: 'Admin' },
{ id: '2', name: 'Bob', role: 'User' },
];
function UserRow({ name, role }) {
return (
<View style={{ padding: 12, borderBottomWidth: 1, borderBottomColor: '#eee' }}>
<Text style={{ fontWeight: 'bold' }}>{name}</Text>
<Text style={{ color: '#666' }}>{role}</Text>
</View>
);
}
export default function UserList() {
return (
<View>
{users.map(user => (
<UserRow key={user.id} {...user} />
))}
</View>
);
}TypeScript Props with Interfaces
In TypeScript, define the shape of your props using an interface or type. This catches errors at compile time — passing a number where a string is expected, or forgetting a required prop, shows an error before you even run the app. Mark optional props with ?. TypeScript also enables editor auto-complete: when you type <MyComponent in JSX, your editor lists all available props and their types. This is one of the biggest productivity benefits of using TypeScript in React Native projects.
import { View, Text, StyleSheet } from 'react-native';
interface ProductCardProps {
id: string;
name: string;
price: number;
imageUri: string;
badge?: string; // optional
onPress?: () => void; // optional callback
}
export default function ProductCard({
name,
price,
imageUri,
badge,
onPress,
}: ProductCardProps) {
return (
<View style={styles.card}>
<Text style={styles.name}>{name}</Text>
<Text style={styles.price}>${price.toFixed(2)}</Text>
{badge && <Text style={styles.badge}>{badge}</Text>}
</View>
);
}
const styles = StyleSheet.create({
card: { padding: 16, backgroundColor: '#fff', borderRadius: 12 },
name: { fontSize: 16, fontWeight: '600' },
price: { fontSize: 18, color: '#4f86f7', fontWeight: 'bold', marginTop: 4 },
badge: { color: '#e74c3c', fontSize: 12, marginTop: 4 },
});Callback Props: Child to Parent Communication
Since data flows only downward in React, a child communicates back to its parent by calling a callback function passed as a prop. The parent defines the function (what should happen when the user acts), passes it to the child, and the child calls it at the right time. This is the standard pattern for buttons, form inputs, and list items — the child component doesn't care about what happens next (no business logic), it just calls the prop function with any relevant data.
import { View, Text, TouchableOpacity } from 'react-native';
// Child: knows nothing about business logic
function DeleteButton({ itemId, onDelete }) {
return (
<TouchableOpacity onPress={() => onDelete(itemId)}>
<Text style={{ color: 'red' }}>Delete</Text>
</TouchableOpacity>
);
}
// Parent: owns the logic and state
export default function ItemList() {
const [items, setItems] = React.useState(['Apple', 'Banana', 'Cherry']);
function handleDelete(index) {
setItems(prev => prev.filter((_, i) => i !== index));
}
return (
<View>
{items.map((item, i) => (
<View key={i} style={{ flexDirection: 'row', justifyContent: 'space-between', padding: 12 }}>
<Text>{item}</Text>
<DeleteButton itemId={i} onDelete={handleDelete} />
</View>
))}
</View>
);
}Avoiding Prop Drilling
Prop drilling happens when you pass props through several intermediate components that don't need the data themselves — they just forward it deeper. For example, passing a user object from App → Screen → Section → Card → Avatar just to display the avatar image. This becomes difficult to maintain as the hierarchy grows. The solution is to use Context (for global or shared data like the logged-in user or theme) or to colocate state closer to the components that need it. Don't over-engineer early — a few levels of prop passing is perfectly fine.
// Prop drilling anti-pattern (not ideal when deep)
function App() {
const user = { name: 'Alice', avatar: 'https://...' };
return <Screen user={user} />;
}
function Screen({ user }) {
return <Section user={user} />; // just passing through
}
function Section({ user }) {
return <Avatar user={user} />; // just passing through
}
function Avatar({ user }) {
return <Image source={{ uri: user.avatar }} style={{ width: 40, height: 40 }} />; // actually uses it
}
// Solution: Context (covered later)
// Or: pass only the specific value needed at each level
function Section({ avatarUri }) { ... }
function Avatar({ uri }) { ... }Immutable Props: Why Children Cannot Modify Them
A core rule of React: a component must never modify its own props. Props are the parent's data passed to the child for display — they are owned by the parent. If a child needs to change a value, it should call a callback prop to tell the parent, and the parent updates its state. The parent then passes the updated value back down as a new prop. This unidirectional flow makes data changes predictable and debuggable — you always know where state lives and who controls it.
// WRONG: Never mutate props directly
function Counter({ count }) {
// This is an error — do not do this:
// count = count + 1;
return <Text>{count}</Text>;
}
// CORRECT: Notify parent via callback, parent updates state
function Counter({ count, onIncrement }) {
return (
<TouchableOpacity onPress={onIncrement}>
<Text>{count}</Text>
</TouchableOpacity>
);
}
// In the parent:
const [count, setCount] = useState(0);
<Counter count={count} onIncrement={() => setCount(c => c + 1)} />Real-World Props Example: Feed Post
Apply all prop concepts to a realistic social media feed post component. The component receives data from the feed list (text, image, author, like count, timestamp) and callback functions for user interactions (like, comment, share). The component is purely presentational — all data comes in through props, all interactions flow out through callback props. This design makes the FeedPost component easy to test in isolation and reuse across different feed types (home feed, profile feed, search results).
import { View, Text, Image, TouchableOpacity, StyleSheet } from 'react-native';
export default function FeedPost({
author, avatarUri, imageUri, caption, likes, timeAgo,
onLike, onComment, onShare
}) {
return (
<View style={styles.post}>
<View style={styles.header}>
<Image source={{ uri: avatarUri }} style={styles.avatar} />
<View>
<Text style={styles.author}>{author}</Text>
<Text style={styles.time}>{timeAgo}</Text>
</View>
</View>
<Image source={{ uri: imageUri }} style={styles.postImage} />
<Text style={styles.caption}>{caption}</Text>
<View style={styles.actions}>
<TouchableOpacity onPress={onLike}><Text>❤️ {likes}</Text></TouchableOpacity>
<TouchableOpacity onPress={onComment}><Text>💬 Comment</Text></TouchableOpacity>
<TouchableOpacity onPress={onShare}><Text>🔗 Share</Text></TouchableOpacity>
</View>
</View>
);
}
const styles = StyleSheet.create({
post: { backgroundColor: '#fff', marginBottom: 8 },
header: { flexDirection: 'row', alignItems: 'center', padding: 12, gap: 10 },
avatar: { width: 40, height: 40, borderRadius: 20 },
author: { fontWeight: 'bold', fontSize: 14 },
time: { fontSize: 12, color: '#999' },
postImage: { width: '100%', aspectRatio: 1 },
caption: { padding: 12, fontSize: 14 },
actions: { flexDirection: 'row', gap: 20, padding: 12, borderTopWidth: 1, borderTopColor: '#eee' },
});Default Props with defaultProps
In addition to destructuring defaults, React components can define defaultProps as a static property — a plain object that specifies fallback values for each optional prop. When a prop is undefined (not passed by the parent), React substitutes the value from defaultProps. This pattern is older than destructuring defaults and works the same way, but is less common in modern TypeScript codebases where interface defaults are preferred. Both approaches achieve the same result: making optional props safe to consume without null checks.
import { Text, View, StyleSheet } from 'react-native';
function Avatar({ size, color, initials }) {
return (
<View style={[styles.circle, { width: size, height: size, borderRadius: size / 2, backgroundColor: color }]}>
<Text style={styles.initials}>{initials}</Text>
</View>
);
}
// defaultProps: applied when prop is undefined
Avatar.defaultProps = {
size: 48,
color: '#4f86f7',
};
// Usage:
<Avatar initials='AB' /> // uses defaults: 48px blue
<Avatar initials='CD' size={64} /> // custom size, default color
<Avatar initials='EF' size={32} color='#e74c3c' /> // all custom
const styles = StyleSheet.create({
circle: { alignItems: 'center', justifyContent: 'center' },
initials: { color: '#fff', fontWeight: 'bold', fontSize: 16 },
});Quick Check
Test your understanding of React Native Mobile Development concepts from this lesson.
Lesson Recap
In this lesson you learned: props are read-only values passed from parent to child in one direction, callback function props allow children to notify parents of user actions, and TypeScript interfaces document and enforce the expected prop shape at compile time. Next up we explore managing changing values inside components with the useState hook.
Sıkça Sorulan Sorular
“Props ile Veri Aktarma” dersi ücretsiz mi?
Evet — “Props ile Veri Aktarma” dersin tüm metni burada web'de ücretsiz olarak okunabilir. Etkileşimli olarak pratik yapmak (yerleşik kod editörü ve 7/24 yapay zeka koçu) ve React Native Academy kursunun geri kalanını açmak için CoddyKit PRO'ya yükselt. React Native Academy kursu toplamda 4 dersten oluşur.
“Props ile Veri Aktarma” dersinde ne öğreneceğim?
Props kabul eden yeniden kullanılabilir bir bileşen tanımlayın, değerleri üst bileşenden aktarın ve beklenen prop yapılarını belgelemek için PropTypes veya TypeScript kullanın. React Native Academy ile uygulamalı kodu tarayıcıda doğrudan çalıştırarak pratik yaparsın ve 7/24 yapay zeka koçu dersi çalışırken sorularını yanıtlar.
React Native Academy öğrenmeye başlamak için deneyim gerekli mi?
Önceden deneyim gerekmez. CoddyKit'te React Native Academy, başlangıçtan ileri seviyeye kadar yapılandırıldığı için buradan başlayabilir veya başından başlayıp kendi hızında ilerleme yapabilirsin. Bu, 4 dersinin 1. dersidir.
“Props ile Veri Aktarma” dersi ne kadar sürer?
Çoğu CoddyKit dersi yaklaşık 5–10 dakika sürer. Her biri kısa ve etkileşimli olduğu için sabit ilerleme yaparsın ve web ile uygulama arasında tam olarak bıraktığın yerden devam edebilirsin.
Bu React Native Academy dersinde kod yazıp çalıştırabilir miyim?
Evet. Her React Native Academy dersi yerleşik bir kod editörü içerir, bu sayede tarayıcıda gerçek kod yazıp çalıştırabilir ve anlık yapay zeka geri bildirimi alırsın — yerel kurulum gerekli değildir.
Bu kursun tüm dersleri
- Props ile Veri Aktarma
- useState ile Bileşen Durumunu Yönetme
- Durumu Üst Düzeye Taşıma
- Etkileşimli Sayaç Uygulaması Oluşturma