Event handlers con parámetros personalizados
Clase 12 de 58 • Curso Profesional de React con Redux 2016
Contenido del curso
Fundamentos
- 3

¿Qué es React?
05:12 min - 4

Hola Mundo con React
07:31 min - 5

¿Qué es y cómo funciona el Virtual DOM?
05:39 min - 6

Introducción a JSX
03:58 min - 7

Creación de componentes
13:21 min - 8

Componentes Puros vs de Estado
03:57 min - 9

Ciclo de vida de un componente
10:23 min - 10

Ciclo de vida de componentes
04:19 min - 11

Manejo de eventos del DOM
04:31 min - 12

Event handlers con parámetros personalizados
Viendo ahora - 13

Contexto de la aplicación
05:19 min - 14

Componentes de Alto Orden (HOC) y Mixins
08:22 min
Creación del proyecto
- 15

Presentación del proyecto
01:01 min - 16

Instalación de Node.js y usando npm
04:44 min - 17

Estructura de archivos
05:02 min - 18

Iniciar un servidor de render básico - Render en Server
03:40 min - 19

Module bundlers en JavaScript
06:02 min - 20

Configurar Webpack para el servidor de render
09:23 min - 21

Crear una app con React y React Router
04:21 min - 22

Manejo de rutas en el servidor con React Router
14:45 min - 23

Crear cliente para consumir el API
05:04 min - 24

Iniciar la app en el navegador y configurar Webpack para producción
08:58 min - 25

Iniciar un servidor de estáticos con zeit/list
04:33 min - 26

Herramientas de desarrollo de React
03:22 min - 27

Consumir el API y mostrar datos en la home
10:16 min - 28

Perfil de usuarios
08:13 min - 29

Estado de cargando y detalle de post
07:46 min - 30

Paginación de posts mediante scroll infinito
06:42 min - 31

Mostrar listado de comentarios en cada post
02:56 min - 32

Estilizar componentes con CSS Modules
18:43 min - 33

Linter y buenas prácticas con ESLint
22:21 min - 34

Internacionalización con React Intl
17:57 min - 35

Deploy a producción
27:30 min
Implementación de Redux
- 36

Patrones de arquitectura de aplicaciones Frontend
05:35 min - 37

Implementación inicial con Redux para los posts
20:37 min - 38

Uso de middlewares
08:39 min - 39

Acciones asíncronas
09:11 min - 40

Dividir el reducer en funciones más pequeñas y combinarlas
12:16 min - 41

Datos inmutables con Immutable.js
14:00 min - 42

Herramientas de desarrollo
08:08 min - 43

Conclusiones
02:02 min - 44

Pruebas automatizadas de reducers
09:03 min - 45

Pruebas de componentes de React
10:33 min - 46

Actualizando a la última versión de React Router
03:51 min
Desafíos
Contenido bonus
- 51

Glosario
03:47 min - 52

Evitar que webpack genere el CSS durante el build del servidor
00:57 min - 53

LazyLoad de imágenes
08:07 min - 54

Animaciones con ReactCSSTransitionGroup
07:31 min - 55

Server render con Next.js
11:53 min - 56

Aplicaciones universales/isomórficas
02:04 min - 57

Iniciar proyectos con create-react-app
04:34 min - 58

Diplomado de desarrollo de aplicaciones con ReactJS
00:38 min
Cuando creamos componentes cada vez más complejos es posible que necesitemos pasar parámetros personalizados a una función que usemos para manejar eventos. En estos casos hay varias formas de manejar esto.
Usando el patrón factory
class App extends React.Component { constructor(props) { super(props); this.state = { name: 'platzi' }; } handleClick(name) { return event => { this.setState({ name: name.split('').reverse().join('') }); }; } render() { return ( <button onClick={this.handleClick(this.state.name)}> Click me {this.state.name}! <button> ); } }
Esta es una forma muy común de hacerlo donde estamos usando el patrón factory para tener una función (this.handleClick) la cual crea una nueva función cada vez que se ejecute y le permite a esta función acceder a los parámetros que reciba nuestro factory.
Usando arrow functions
class App extends React.Component { constructor(props) { super(props); this.state = { name: 'platzi' }; } handleClick(name, event) { this.setState({ name: name.split('').reverse().join('') }); } render() { return ( <button onClick={event => this.handleClick(this.state.name, event)}> Click me {this.state.name}! <button> ); } }
De forma similar se pueden usar arrow functions, en este caso en el render creamos una función que recibe event y ejecuta this.handleClick pasándo this.state.name y el event que recibimos. Lo que hace el arrow function es básicamente ser un factory function igual que en el primer método.
El problema de estos dos métodos es que cada vez que hacemos un render del componente (cuando se actualizan los props o el state) estamos creando de nuevo estas funciones. En el ejemplo pasa exactamente esto, lo que podemos notar al ver que el valor de this.state.name se invierte cada vez que hacemos click en el botón.
En general esto puede causar un problema de que estemos creando muchas funciones innecesariamente. Para solucionar esto podemos crear una especie de cache de nuestras funciones.
Cache de funciones
class App extends React.Component { constructor(props) { super(props); this.state = { name: 'platzi' }; this.cache = {}; } handleClick(name) { return event => { this.setState({ name: name.split('').reverse().join('') }); }; } render() { let handleClick = this.cache[this.state.name]; if (!handleClick) { handleClick = this.handleClick(this.state.name); this.cache[this.state.name] = handleClick; } return ( <button onClick={handleClick}> Click me {this.state.name}! <button> ); } }
De esta forma si ya creamos una vez la función con el parámetro deseado podemos usar esa función y si el valor de this.state.name cambió creamos una nueva función y la guardamos en cache.
El único problema de esto sería que podemos llegar a tener muchas funciones en nuestra cache, en ese caso necesitaríamos de alguna forma empezar a limpiarla para eliminar funciones que ya no se usan y evitar problemas de memoria.
Una mejor forma de hacer esto es usar una técnica de programación funcional llamada aplicación parcial (partial application o papp) para crear estas funciones solo una vez y cuando se necesiten.
Aplicación parcial
function handleClick(name, event) { return this.setState({ name: name.split('').reverse().join(''), }); } class App extends Component { constructor(props) { super(props); this.state = { name: 'Platzi' }; this.handleClick = handleClick.bind(this, this.state.name); } componentWillUpdate(nextProps, nextState) { if (nextState.name !== this.state.name) { this.handleClick = handleClick.bind(this, nextState.name); } } render() { return ( <button onClick={this.handleClick}> Click me {this.state.name}! </button> ); } }
La aplicación parcial de una función consiste en que en vez de ejecutar completamente una función lo que hacemos es pasarle parte de los parámetros que esta recibe (aplicarla parcialmente) y obtener una nueva función a la cual podemos pasarle el resto de parámetros.
Usando esta idea podemos crear una función (por fuera de nuestro componente) la cual recibe el name (nuestro parámetros personalizado) y el event (que recibe la función al ser un event handler).
Luego en nuestro constructor podemos hacer bind de dicha función y resulta que al hacer este bind no solo podemos pasar el valor de this (el cual nos va a servir para poder actualizar el estado) si no que además podemos pasar N cantidad de parámetros extras y estos van a ser aplicados a la función a la que estamos haciendo bind.
Un ejemplo rápido y simple
const sumar = (n1, n2) => n1 + n2; const sumar5 = sumar.bind(null, 5); console.log(sumar5(10)); // 10
Gracias a poder pasar otros parámetros a bind podemos pasar el valor inicial de this.state.name. Luego cuando el componente se vaya a actualizar (componentWillUpdate) verificamos si el name del nuevo estado es diferente del actual y en caso de serlo volvemos a hacer el bind y actualizamos la función this.handleClick para que ahora name sea el nuevo valor. De esta forma reducimos la cantidad de veces que hacemos bind a solo cuando sea necesario.
También podríamos usar los
propsen vez delstatede la misma forma, para que si cambian estos volvamos a hacer elbind, o incluso combinarlos para usar tantopropscomostateen elbind.
Hay que destacar que la razón para tener handleClick por fuera del componente y usar este cada vez que hacemos el bind es que si hiciésemos bind dos veces sobre la misma función el nuevo valor de name pasaría a llegar como event, en cambio al usar siempre la misma función base sin el bind nos evitamos este problema.
Conclusiones
Como vemos hay varias formas, seguramente se les puedan ocurrir otras, la primer forma es la más simple (tanto usar factory como arrow functions), usar una cache es más bien un hack para evitar los problemas de la primer forma, usar papp sin duda la que tiene menos problemas de rendimiento y la que tiene más sentido con la orientación a programación funcional que posee React.js.