20. Formas de crear Componentes
Tutorial: Formas de Crear Componentes en React Native
En este tutorial aprenderás las dos formas principales de crear componentes en React Native: Functional Components y Class Components, y cuándo usar cada una.
🎯 Objetivo del Tutorial
Comprender las dos formas de crear componentes en React Native, sus diferencias, ventajas y casos de uso.
📊 Comparación de las Dos Formas
🛠️ Parte 1: Functional Components
Ejemplo Básico:
tsx
// src/components/MiPrimerComponente/MiPrimerComponente.tsx
import React from 'react';
import {StyleSheet, View, ViewStyle} from 'react-native';
// Functional Component
function MiPrimerComponente(): JSX.Element {
return <View style={styles.mainComponent} />;
}
// Estilos
export const styles = StyleSheet.create({
mainComponent: {
width: 50,
height: 50,
backgroundColor: 'red',
borderRadius: 25,
borderColor: 'green',
borderWidth: 5,
} as ViewStyle,
});
export default MiPrimerComponente;
Características:
Función simple que retorna JSX
No usa this
Más fácil de leer y probar
Hooks para estado y efectos
Con Props:
tsx
// Componente con propiedades
interface MiComponenteProps {
color?: string;
tamaño?: number;
}
function MiComponente({color = 'red', tamaño = 50}: MiComponenteProps): JSX.Element {
return (
<View
style={{
width: tamaño,
height: tamaño,
backgroundColor: color,
borderRadius: tamaño / 2,
}}
/>
);
}
🏗️ Parte 2: Class Components
Ejemplo Básico:
tsx
// src/components/MiPrimerComponenteClass/MiPrimerComponenteClass.tsx
import React from 'react';
import {StyleSheet, View, ViewStyle} from 'react-native';
// Class Component
class MiPrimerComponenteClass extends React.Component {
render(): React.ReactNode {
return <View style={styles.mainComponent} />;
}
}
// Estilos
export const styles = StyleSheet.create({
mainComponent: {
width: 50,
height: 50,
backgroundColor: 'blue', // Diferente color para distinguir
borderRadius: 25,
borderColor: 'green',
borderWidth: 5,
} as ViewStyle,
});
export default MiPrimerComponenteClass;
Características:
Clase que extiende React.Component
Usa this para acceder a props y state
Método render() obligatorio
Métodos de ciclo de vida
Estructura Completa:
tsx
import React from 'react';
import {View, Text} from 'react-native';
interface Props {
mensaje: string;
}
interface State {
contador: number;
activo: boolean;
}
class MiClaseComponent extends React.Component<Props, State> {
constructor(props: Props) {
super(props);
this.state = {
contador: 0,
activo: true,
};
}
componentDidMount() {
console.log('Componente montado');
}
componentDidUpdate() {
console.log('Componente actualizado');
}
componentWillUnmount() {
console.log('Componente desmontado');
}
incrementar = () => {
this.setState(prevState => ({
contador: prevState.contador + 1,
}));
};
render() {
return (
<View>
<Text>{this.props.mensaje}</Text>
<Text>Contador: {this.state.contador}</Text>
</View>
);
}
}
🔄 Parte 3: Usar Ambos Componentes en App.tsx
Importar y usar ambos componentes:
tsx
// App.tsx
import React from 'react';
import {SafeAreaView} from 'react-native';
import MiPrimerComponente from './src/components/MiPrimerComponente/MiPrimerComponente';
import MiPrimerComponenteClass from './src/components/MiPrimerComponenteClass/MiPrimerComponenteClass';
function App(): JSX.Element {
return (
<SafeAreaView style={{flex: 1, justifyContent: 'center', alignItems: 'center'}}>
{/* Functional Component */}
<MiPrimerComponente />
{/* Class Component */}
<MiPrimerComponenteClass />
{/* Reutilizar componentes */}
<MiPrimerComponente />
<MiPrimerComponente />
</SafeAreaView>
);
}
export default App;
Resultado Visual:
Círculo rojo: Functional Component
Círculo azul: Class Component
Misma sintaxis de uso: <NombreComponente />
📝 Parte 4: Diferencias Detalladas
1. Manejo de Props:
Functional Component:
tsx
// Props como parámetro de función
function Saludo({nombre, edad}: {nombre: string; edad: number}) {
return <Text>Hola {nombre}, tienes {edad} años</Text>;
}
Class Component:
tsx
// Props accesibles via this.props
class Saludo extends React.Component<{nombre: string; edad: number}> {
render() {
return (
<Text>
Hola {this.props.nombre}, tienes {this.props.edad} años
</Text>
);
}
}
2. Manejo de Estado:
Functional Component (useState Hook):
tsx
import React, {useState} from 'react';
function Contador() {
const [contador, setContador] = useState(0);
return (
<View>
<Text>Contador: {contador}</Text>
<Button title="Incrementar" onPress={() => setContador(contador + 1)} />
</View>
);
}
Class Component (this.state):
tsx
class Contador extends React.Component {
constructor(props) {
super(props);
this.state = {
contador: 0,
};
}
incrementar = () => {
this.setState({contador: this.state.contador + 1});
};
render() {
return (
<View>
<Text>Contador: {this.state.contador}</Text>
<Button title="Incrementar" onPress={this.incrementar} />
</View>
);
}
}
3. Ciclo de Vida:
Functional Component (useEffect Hook):
tsx
import React, {useEffect} from 'react';
function MiComponente() {
useEffect(() => {
// componentDidMount
console.log('Componente montado');
return () => {
// componentWillUnmount
console.log('Componente desmontado');
};
}, []);
return <View />;
}
Class Component (Métodos):
tsx
class MiComponente extends React.Component {
componentDidMount() {
console.log('Componente montado');
}
componentDidUpdate(prevProps, prevState) {
console.log('Componente actualizado');
}
componentWillUnmount() {
console.log('Componente desmontado');
}
render() {
return <View />;
}
}
🎯 Parte 5: Cuándo Usar Cada Uno
Usar Functional Components cuando:
✅ Proyectos nuevos - Es la forma moderna
✅ Componentes simples - Sin lógica compleja
✅ Reutilización de lógica - Con Custom Hooks
✅ Performance - Más ligeros que las clases
✅ Testing - Más fáciles de probar
Usar Class Components cuando:
⚠️ Mantener código legacy - Proyectos existentes
⚠️ Necesitas Error Boundaries - Manejo de errores
⚠️ Componentes muy complejos - Con mucha lógica de ciclo de vida
⚠️ Preferencia personal - Si te sientes más cómodo
🔧 Parte 6: Convertir entre Ambos
De Class a Functional Component:
tsx
// Class Component original
class ContadorClase extends React.Component {
state = {contador: 0};
incrementar = () => {
this.setState({contador: this.state.contador + 1});
};
render() {
return (
<View>
<Text>{this.state.contador}</Text>
<Button title="+" onPress={this.incrementar} />
</View>
);
}
}
// Functional Component equivalente
function ContadorFuncional() {
const [contador, setContador] = useState(0);
const incrementar = () => {
setContador(contador + 1);
};
return (
<View>
<Text>{contador}</Text>
<Button title="+" onPress={incrementar} />
</View>
);
}
De Functional a Class Component:
tsx
// Functional Component original
function SaludoFuncional({nombre}: {nombre: string}) {
return <Text>Hola {nombre}</Text>;
}
// Class Component equivalente
class SaludoClase extends React.Component<{nombre: string}> {
render() {
return <Text>Hola {this.props.nombre}</Text>;
}
}
🧪 Parte 7: Ejercicio Práctico - Crear Ambos Tipos
Ejercicio 1: Botón con Contador
Functional Component:
tsx
// src/components/ContadorFuncional/ContadorFuncional.tsx
import React, {useState} from 'react';
import {View, Text, Button, StyleSheet} from 'react-native';
function ContadorFuncional(): JSX.Element {
const [contador, setContador] = useState(0);
const incrementar = () => setContador(contador + 1);
const decrementar = () => setContador(contador - 1);
const reset = () => setContador(0);
return (
<View style={styles.container}>
<Text style={styles.texto}>Contador: {contador}</Text>
<View style={styles.botones}>
<Button title="-" onPress={decrementar} />
<Button title="Reset" onPress={reset} />
<Button title="+" onPress={incrementar} />
</View>
</View>
);
}
const styles = StyleSheet.create({
container: {
padding: 20,
margin: 10,
backgroundColor: '#f0f0f0',
borderRadius: 10,
},
texto: {
fontSize: 24,
textAlign: 'center',
marginBottom: 20,
},
botones: {
flexDirection: 'row',
justifyContent: 'space-around',
},
});
export default ContadorFuncional;
Class Component:
tsx
// src/components/ContadorClase/ContadorClase.tsx
import React from 'react';
import {View, Text, Button, StyleSheet} from 'react-native';
interface State {
contador: number;
}
class ContadorClase extends React.Component<{}, State> {
constructor(props: {}) {
super(props);
this.state = {
contador: 0,
};
}
incrementar = () => {
this.setState(prevState => ({
contador: prevState.contador + 1,
}));
};
decrementar = () => {
this.setState(prevState => ({
contador: prevState.contador - 1,
}));
};
reset = () => {
this.setState({contador: 0});
};
render() {
return (
<View style={styles.container}>
<Text style={styles.texto}>Contador: {this.state.contador}</Text>
<View style={styles.botones}>
<Button title="-" onPress={this.decrementar} />
<Button title="Reset" onPress={this.reset} />
<Button title="+" onPress={this.incrementar} />
</View>
</View>
);
}
}
// Mismos estilos que el componente funcional
const styles = StyleSheet.create({
container: {
padding: 20,
margin: 10,
backgroundColor: '#f0f0f0',
borderRadius: 10,
},
texto: {
fontSize: 24,
textAlign: 'center',
marginBottom: 20,
},
botones: {
flexDirection: 'row',
justifyContent: 'space-around',
},
});
export default ContadorClase;
Ejercicio 2: Mostrar Ambos en App.tsx
tsx
// App.tsx
import React from 'react';
import {SafeAreaView, ScrollView} from 'react-native';
import ContadorFuncional from './src/components/ContadorFuncional/ContadorFuncional';
import ContadorClase from './src/components/ContadorClase/ContadorClase';
function App(): JSX.Element {
return (
<SafeAreaView style={{flex: 1}}>
<ScrollView contentContainerStyle={{padding: 20}}>
<ContadorFuncional />
<ContadorClase />
</ScrollView>
</SafeAreaView>
);
}
export default App;
⚠️ Parte 8: Consideraciones y Advertencias
Error Boundaries (Solo Class Components):
tsx
// Solo posible con Class Components
class ErrorBoundary extends React.Component {
constructor(props) {
super(props);
this.state = {hasError: false};
}
static getDerivedStateFromError(error) {
return {hasError: true};
}
componentDidCatch(error, errorInfo) {
console.log('Error:', error, errorInfo);
}
render() {
if (this.state.hasError) {
return <Text>Algo salió mal</Text>;
}
return this.props.children;
}
}
Refs (Referencias):
tsx
// Functional Component con useRef
function MiComponente() {
const inputRef = useRef(null);
useEffect(() => {
inputRef.current.focus();
}, []);
return <TextInput ref={inputRef} />;
}
// Class Component con createRef
class MiComponente extends React.Component {
inputRef = React.createRef();
componentDidMount() {
this.inputRef.current.focus();
}
render() {
return <TextInput ref={this.inputRef} />;
}
}
📚 Parte 9: Migración y Mejores Prácticas
Migrar de Class a Functional:
Reemplazar this.state con useState
Reemplazar métodos de ciclo de vida con useEffect
Convertir métodos a funciones dentro del componente
Eliminar constructor y super()
Usar props directamente como parámetro
Código Legacy vs Moderno:
tsx
// Legacy (2018) - Class Components
class App extends React.Component {
render() {
return <View>Hola</View>;
}
}
// Modern (2023+) - Functional Components
const App = () => {
return <View>Hola</View>;
};
✅ Resumen y Recomendaciones
Para Nuevos Desarrolladores:
Aprende Functional Components primero
Domina Hooks (useState, useEffect)
Solo estudia Class Components si encuentras código legacy
Para Proyectos Existentes:
Nuevos componentes: Usar Functional
Componentes existentes: Mantener como están
Refactorizar solo si hay beneficio claro
Regla de Oro:
"Usa Functional Components para todo lo nuevo, aprende Class Components para entender código existente"
🎉 ¡Felicidades!
Has aprendido las dos formas de crear componentes en React Native:
✅ Functional Components - La forma moderna con Hooks
✅ Class Components - La forma tradicional con métodos
✅ Diferencias entre ambos enfoques
✅ Cuándo usar cada uno según el contexto
✅ Cómo convertir entre ambos tipos
✅ Ejercicios prácticos para aplicar el conocimiento
🔮 Tendencia del Mercado:
2018-2020: Transición de Class a Functional
2021+: Functional Components dominantes
Hooks: Standard para estado y efectos
Class Components: Solo para código legacy o casos específicos
¡Excelente trabajo! Ahora tienes el conocimiento completo sobre componentes en React Native. En los próximos tutoriales profundizaremos en Props, State y Eventos.
Comentarios
Publicar un comentario