Transmisión de datos mediante props
Defina un componente reutilizable que acepte props, pase valores desde un componente padre y utilice PropTypes o TypeScript para documentar las formas esperadas de las props.
Transmisión de datos mediante props es una lección gratuita de React Native Academy en CoddyKit. Esta es la lección 1 de 4. Puedes leer la lección completa abajo gratuitamente — luego la practicas en el navegador con un editor de código integrado y un tutor de IA 24/7. Forma parte de la ruta de aprendizaje de React Native Academy, y tu progreso se sincroniza en la web y la app de CoddyKit. El curso de React Native Academy incluye 4 lecciones en total.
Partes de esta lección aún no han sido traducidas y se muestran en inglés.
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.
Preguntas frecuentes
¿La lección «Transmisión de datos mediante props» es gratis?
Sí — el texto completo de «Transmisión de datos mediante props» es gratis para leer aquí en la web. Para practicarla de forma interactiva (editor de código integrado y tutor de IA 24/7) y desbloquear el resto del curso de React Native Academy, actualiza a CoddyKit PRO. El curso de React Native Academy incluye 4 lecciones en total.
¿Qué aprenderé en «Transmisión de datos mediante props»?
Defina un componente reutilizable que acepte props, pase valores desde un componente padre y utilice PropTypes o TypeScript para documentar las formas esperadas de las props. Practicas React Native Academy con código real que ejecutas directamente en el navegador, y un tutor de IA 24/7 responde tus preguntas mientras trabajas en la lección.
¿Necesito experiencia previa para empezar React Native Academy?
No se requiere experiencia previa. React Native Academy en CoddyKit está estructurado para principiantes hasta estudiantes avanzados, así que puedes empezar aquí o desde el inicio y avanzar a tu ritmo. Esta es la lección 1 de 4.
¿Cuánto tiempo toma la lección «Transmisión de datos mediante props»?
La mayoría de las lecciones de CoddyKit toman alrededor de 5–10 minutos. Cada una es compacta e interactiva, así que avanzas constantemente y retomas exactamente por donde dejaste en la web y la app.
¿Puedo escribir y ejecutar código en esta lección de React Native Academy?
Sí. Cada lección de React Native Academy incluye un editor de código integrado, así que escribes y ejecutas código real directamente en tu navegador y obtienes retroalimentación instantánea de IA — sin configuración local necesaria.
Todas las lecciones de este curso
- Transmisión de datos mediante props
- Gestión del estado de componentes con useState
- Elevación del estado
- Creación de una aplicación de contador interactiva