Integrando React.js en aplicaciones Symfony (deSymfony 2016)
-
Upload
ignacio-martin -
Category
Software
-
view
771 -
download
1
Transcript of Integrando React.js en aplicaciones Symfony (deSymfony 2016)
![Page 1: Integrando React.js en aplicaciones Symfony (deSymfony 2016)](https://reader033.fdocumento.com/reader033/viewer/2022061610/58720ee81a28ab176b8b8217/html5/thumbnails/1.jpg)
deSymfony 16-17 septiembre 2016 Madrid
INTEGRANDO REACT.JS EN APLICACIONES SYMFONYNacho Martín
![Page 2: Integrando React.js en aplicaciones Symfony (deSymfony 2016)](https://reader033.fdocumento.com/reader033/viewer/2022061610/58720ee81a28ab176b8b8217/html5/thumbnails/2.jpg)
deSymfony
¡Muchas gracias a nuestros patrocinadores!
![Page 3: Integrando React.js en aplicaciones Symfony (deSymfony 2016)](https://reader033.fdocumento.com/reader033/viewer/2022061610/58720ee81a28ab176b8b8217/html5/thumbnails/3.jpg)
Programo en Limenius
Casi todos los proyectos necesitan un frontend rico, por una razón o por otra
Hacemos aplicaciones a medida
Así que le hemos dado unas cuantas vueltas
![Page 4: Integrando React.js en aplicaciones Symfony (deSymfony 2016)](https://reader033.fdocumento.com/reader033/viewer/2022061610/58720ee81a28ab176b8b8217/html5/thumbnails/4.jpg)
Objetivo: Mostrar cosas que nos encontramos al usar React desde Symfony, en tierra de nadie, y que ninguno de los dos va a documentar.
![Page 5: Integrando React.js en aplicaciones Symfony (deSymfony 2016)](https://reader033.fdocumento.com/reader033/viewer/2022061610/58720ee81a28ab176b8b8217/html5/thumbnails/5.jpg)
¿A mí qué me importa el frontend?
![Page 6: Integrando React.js en aplicaciones Symfony (deSymfony 2016)](https://reader033.fdocumento.com/reader033/viewer/2022061610/58720ee81a28ab176b8b8217/html5/thumbnails/6.jpg)
![Page 7: Integrando React.js en aplicaciones Symfony (deSymfony 2016)](https://reader033.fdocumento.com/reader033/viewer/2022061610/58720ee81a28ab176b8b8217/html5/thumbnails/7.jpg)
¿Qué es React.js?
![Page 8: Integrando React.js en aplicaciones Symfony (deSymfony 2016)](https://reader033.fdocumento.com/reader033/viewer/2022061610/58720ee81a28ab176b8b8217/html5/thumbnails/8.jpg)
Echar huevos en sartén
La premisa fundamental
Cómo hacer una tortillaComprar huevos
Romper huevos
![Page 9: Integrando React.js en aplicaciones Symfony (deSymfony 2016)](https://reader033.fdocumento.com/reader033/viewer/2022061610/58720ee81a28ab176b8b8217/html5/thumbnails/9.jpg)
Echar huevos en sartén
Batir huevos
La premisa fundamental
Cómo hacer una tortillaComprar huevos
Romper huevos
![Page 10: Integrando React.js en aplicaciones Symfony (deSymfony 2016)](https://reader033.fdocumento.com/reader033/viewer/2022061610/58720ee81a28ab176b8b8217/html5/thumbnails/10.jpg)
Opciones:
La premisa fundamental
![Page 11: Integrando React.js en aplicaciones Symfony (deSymfony 2016)](https://reader033.fdocumento.com/reader033/viewer/2022061610/58720ee81a28ab176b8b8217/html5/thumbnails/11.jpg)
Opciones:
La premisa fundamental
1: Repintamos todo.
![Page 12: Integrando React.js en aplicaciones Symfony (deSymfony 2016)](https://reader033.fdocumento.com/reader033/viewer/2022061610/58720ee81a28ab176b8b8217/html5/thumbnails/12.jpg)
Opciones:
La premisa fundamental
1: Repintamos todo. Simple
![Page 13: Integrando React.js en aplicaciones Symfony (deSymfony 2016)](https://reader033.fdocumento.com/reader033/viewer/2022061610/58720ee81a28ab176b8b8217/html5/thumbnails/13.jpg)
Opciones:
La premisa fundamental
1: Repintamos todo. Simple Poco eficiente
![Page 14: Integrando React.js en aplicaciones Symfony (deSymfony 2016)](https://reader033.fdocumento.com/reader033/viewer/2022061610/58720ee81a28ab176b8b8217/html5/thumbnails/14.jpg)
Opciones:
2: Buscamos en el DOM dónde insertar, qué mover, qué eliminar.
La premisa fundamental
1: Repintamos todo. Simple Poco eficiente
![Page 15: Integrando React.js en aplicaciones Symfony (deSymfony 2016)](https://reader033.fdocumento.com/reader033/viewer/2022061610/58720ee81a28ab176b8b8217/html5/thumbnails/15.jpg)
Opciones:
2: Buscamos en el DOM dónde insertar, qué mover, qué eliminar.
La premisa fundamental
1: Repintamos todo. Simple
Complejo
Poco eficiente
![Page 16: Integrando React.js en aplicaciones Symfony (deSymfony 2016)](https://reader033.fdocumento.com/reader033/viewer/2022061610/58720ee81a28ab176b8b8217/html5/thumbnails/16.jpg)
Opciones:
2: Buscamos en el DOM dónde insertar, qué mover, qué eliminar.
La premisa fundamental
1: Repintamos todo. Simple
Muy eficienteComplejo
Poco eficiente
![Page 17: Integrando React.js en aplicaciones Symfony (deSymfony 2016)](https://reader033.fdocumento.com/reader033/viewer/2022061610/58720ee81a28ab176b8b8217/html5/thumbnails/17.jpg)
Opciones:
2: Buscamos en el DOM dónde insertar, qué mover, qué eliminar.
La premisa fundamental
1: Repintamos todo. Simple
Muy eficienteComplejo
Poco eficiente
React nos permite hacer 1, aunque en la sombra hace 2
![Page 18: Integrando React.js en aplicaciones Symfony (deSymfony 2016)](https://reader033.fdocumento.com/reader033/viewer/2022061610/58720ee81a28ab176b8b8217/html5/thumbnails/18.jpg)
Dame un estado y una función render() que dependa de él, y olvídate de cómo y cuándo pinto.*
La premisa fundamental
![Page 19: Integrando React.js en aplicaciones Symfony (deSymfony 2016)](https://reader033.fdocumento.com/reader033/viewer/2022061610/58720ee81a28ab176b8b8217/html5/thumbnails/19.jpg)
Dame un estado y una función render() que dependa de él, y olvídate de cómo y cuándo pinto.*
La premisa fundamental
* A menos que quieras tener control absoluto.
![Page 20: Integrando React.js en aplicaciones Symfony (deSymfony 2016)](https://reader033.fdocumento.com/reader033/viewer/2022061610/58720ee81a28ab176b8b8217/html5/thumbnails/20.jpg)
¡Clícame! Clicks: 0
Nuestro primer componente
![Page 21: Integrando React.js en aplicaciones Symfony (deSymfony 2016)](https://reader033.fdocumento.com/reader033/viewer/2022061610/58720ee81a28ab176b8b8217/html5/thumbnails/21.jpg)
¡Clícame! Clicks: 1
Nuestro primer componente
¡Clícame!
![Page 22: Integrando React.js en aplicaciones Symfony (deSymfony 2016)](https://reader033.fdocumento.com/reader033/viewer/2022061610/58720ee81a28ab176b8b8217/html5/thumbnails/22.jpg)
Nuestro primer componenteimport React, { Component } from 'react';
class Counter extends Component { constructor(props) { super(props); this.state = {count: 1}; }
tick() { this.setState({count: this.state.count + 1}); }
render() { return ( <div className="App"> <button onClick={this.tick.bind(this)}>Clícame!</button> <span>Clicks: {this.state.count}</span> </div> ); }}
export default Counter;
![Page 23: Integrando React.js en aplicaciones Symfony (deSymfony 2016)](https://reader033.fdocumento.com/reader033/viewer/2022061610/58720ee81a28ab176b8b8217/html5/thumbnails/23.jpg)
Nuestro primer componenteimport React, { Component } from 'react';
class Counter extends Component { constructor(props) { super(props); this.state = {count: 1}; }
tick() { this.setState({count: this.state.count + 1}); }
render() { return ( <div className="App"> <button onClick={this.tick.bind(this)}>Clícame!</button> <span>Clicks: {this.state.count}</span> </div> ); }}
export default Counter;
Sintaxis ES6 (opcional)
![Page 24: Integrando React.js en aplicaciones Symfony (deSymfony 2016)](https://reader033.fdocumento.com/reader033/viewer/2022061610/58720ee81a28ab176b8b8217/html5/thumbnails/24.jpg)
Nuestro primer componenteimport React, { Component } from 'react';
class Counter extends Component { constructor(props) { super(props); this.state = {count: 1}; }
tick() { this.setState({count: this.state.count + 1}); }
render() { return ( <div className="App"> <button onClick={this.tick.bind(this)}>Clícame!</button> <span>Clicks: {this.state.count}</span> </div> ); }}
export default Counter;
Sintaxis ES6 (opcional)
Estado inicial
![Page 25: Integrando React.js en aplicaciones Symfony (deSymfony 2016)](https://reader033.fdocumento.com/reader033/viewer/2022061610/58720ee81a28ab176b8b8217/html5/thumbnails/25.jpg)
Nuestro primer componenteimport React, { Component } from 'react';
class Counter extends Component { constructor(props) { super(props); this.state = {count: 1}; }
tick() { this.setState({count: this.state.count + 1}); }
render() { return ( <div className="App"> <button onClick={this.tick.bind(this)}>Clícame!</button> <span>Clicks: {this.state.count}</span> </div> ); }}
export default Counter;
Sintaxis ES6 (opcional)
Modificar estado
Estado inicial
![Page 26: Integrando React.js en aplicaciones Symfony (deSymfony 2016)](https://reader033.fdocumento.com/reader033/viewer/2022061610/58720ee81a28ab176b8b8217/html5/thumbnails/26.jpg)
Nuestro primer componenteimport React, { Component } from 'react';
class Counter extends Component { constructor(props) { super(props); this.state = {count: 1}; }
tick() { this.setState({count: this.state.count + 1}); }
render() { return ( <div className="App"> <button onClick={this.tick.bind(this)}>Clícame!</button> <span>Clicks: {this.state.count}</span> </div> ); }}
export default Counter;
Sintaxis ES6 (opcional)
Modificar estado
render(), lo llama React
Estado inicial
![Page 27: Integrando React.js en aplicaciones Symfony (deSymfony 2016)](https://reader033.fdocumento.com/reader033/viewer/2022061610/58720ee81a28ab176b8b8217/html5/thumbnails/27.jpg)
Trabajar con el estado
![Page 28: Integrando React.js en aplicaciones Symfony (deSymfony 2016)](https://reader033.fdocumento.com/reader033/viewer/2022061610/58720ee81a28ab176b8b8217/html5/thumbnails/28.jpg)
Trabajar con el estado
constructor(props) { super(props); this.state = {count: 1};}
Estado inicial
![Page 29: Integrando React.js en aplicaciones Symfony (deSymfony 2016)](https://reader033.fdocumento.com/reader033/viewer/2022061610/58720ee81a28ab176b8b8217/html5/thumbnails/29.jpg)
Trabajar con el estado
constructor(props) { super(props); this.state = {count: 1};}
Estado inicial
this.setState({count: this.state.count + 1});
Asignar estado
![Page 30: Integrando React.js en aplicaciones Symfony (deSymfony 2016)](https://reader033.fdocumento.com/reader033/viewer/2022061610/58720ee81a28ab176b8b8217/html5/thumbnails/30.jpg)
Trabajar con el estado
constructor(props) { super(props); this.state = {count: 1};}
Estado inicial
this.setState({count: this.state.count + 1});
Asignar estado
this.state.count = this.state.count + 1;
Simplemente recordar evitar
![Page 31: Integrando React.js en aplicaciones Symfony (deSymfony 2016)](https://reader033.fdocumento.com/reader033/viewer/2022061610/58720ee81a28ab176b8b8217/html5/thumbnails/31.jpg)
render() y JSXrender() { return ( <div className="App"> <button onClick={this.tick.bind(this)}>Clícame!</button> <span>Clicks: {this.state.count}</span> </div> );}
No es HTML, es JSX. React lo transforma internamente a elementos. Buena práctica: Dejar render() lo más limpio posible, solo un return.
![Page 32: Integrando React.js en aplicaciones Symfony (deSymfony 2016)](https://reader033.fdocumento.com/reader033/viewer/2022061610/58720ee81a28ab176b8b8217/html5/thumbnails/32.jpg)
render() y JSXrender() { return ( <div className="App"> <button onClick={this.tick.bind(this)}>Clícame!</button> <span>Clicks: {this.state.count}</span> </div> );}
No es HTML, es JSX. React lo transforma internamente a elementos.
Algunas cosas cambian
Buena práctica: Dejar render() lo más limpio posible, solo un return.
![Page 33: Integrando React.js en aplicaciones Symfony (deSymfony 2016)](https://reader033.fdocumento.com/reader033/viewer/2022061610/58720ee81a28ab176b8b8217/html5/thumbnails/33.jpg)
render() y JSXrender() { return ( <div className="App"> <button onClick={this.tick.bind(this)}>Clícame!</button> <span>Clicks: {this.state.count}</span> </div> );}
No es HTML, es JSX. React lo transforma internamente a elementos.
Algunas cosas cambian
Entre {} podemos insertar expresiones JS
Buena práctica: Dejar render() lo más limpio posible, solo un return.
![Page 34: Integrando React.js en aplicaciones Symfony (deSymfony 2016)](https://reader033.fdocumento.com/reader033/viewer/2022061610/58720ee81a28ab176b8b8217/html5/thumbnails/34.jpg)
Thinking in Reactrender() {
return ( <div className="App"> <button onClick={this.tick.bind(this)}>Clícame!</button> <span>Clicks: {this.state.count}</span> </div> );}
![Page 35: Integrando React.js en aplicaciones Symfony (deSymfony 2016)](https://reader033.fdocumento.com/reader033/viewer/2022061610/58720ee81a28ab176b8b8217/html5/thumbnails/35.jpg)
Thinking in Reactrender() {
return ( <div className="App"> <button onClick={this.tick.bind(this)}>Clícame!</button> <span>Clicks: {this.state.count}</span> </div> );}
Aquí no modificar el estado
![Page 36: Integrando React.js en aplicaciones Symfony (deSymfony 2016)](https://reader033.fdocumento.com/reader033/viewer/2022061610/58720ee81a28ab176b8b8217/html5/thumbnails/36.jpg)
Thinking in Reactrender() {
return ( <div className="App"> <button onClick={this.tick.bind(this)}>Clícame!</button> <span>Clicks: {this.state.count}</span> </div> );}
Aquí no Ajax
![Page 37: Integrando React.js en aplicaciones Symfony (deSymfony 2016)](https://reader033.fdocumento.com/reader033/viewer/2022061610/58720ee81a28ab176b8b8217/html5/thumbnails/37.jpg)
Thinking in Reactrender() {
return ( <div className="App"> <button onClick={this.tick.bind(this)}>Clícame!</button> <span>Clicks: {this.state.count}</span> </div> );}
Aquí no calcular decimales de pi y enviar un email
![Page 38: Integrando React.js en aplicaciones Symfony (deSymfony 2016)](https://reader033.fdocumento.com/reader033/viewer/2022061610/58720ee81a28ab176b8b8217/html5/thumbnails/38.jpg)
Importante: pensar la jerarquía
![Page 39: Integrando React.js en aplicaciones Symfony (deSymfony 2016)](https://reader033.fdocumento.com/reader033/viewer/2022061610/58720ee81a28ab176b8b8217/html5/thumbnails/39.jpg)
Importante: pensar la jerarquía
![Page 40: Integrando React.js en aplicaciones Symfony (deSymfony 2016)](https://reader033.fdocumento.com/reader033/viewer/2022061610/58720ee81a28ab176b8b8217/html5/thumbnails/40.jpg)
Jerarquía de componentes: propsclass CounterGroup extends Component { render() { return ( <div> <Counter name="amigo"/> <Counter name="señor"/> </div> ); }}
![Page 41: Integrando React.js en aplicaciones Symfony (deSymfony 2016)](https://reader033.fdocumento.com/reader033/viewer/2022061610/58720ee81a28ab176b8b8217/html5/thumbnails/41.jpg)
render() { return ( <div className="App"> <button onClick={this.tick.bind(this)}> Clícame {this.props.name} </button> <span>Clicks: {this.state.count}</span> </div> );}
y en Counter…
Jerarquía de componentes: propsclass CounterGroup extends Component { render() { return ( <div> <Counter name="amigo"/> <Counter name="señor"/> </div> ); }}
![Page 42: Integrando React.js en aplicaciones Symfony (deSymfony 2016)](https://reader033.fdocumento.com/reader033/viewer/2022061610/58720ee81a28ab176b8b8217/html5/thumbnails/42.jpg)
render() { return ( <div className="App"> <button onClick={this.tick.bind(this)}> Clícame {this.props.name} </button> <span>Clicks: {this.state.count}</span> </div> );}
y en Counter…
Jerarquía de componentes: propsclass CounterGroup extends Component { render() { return ( <div> <Counter name="amigo"/> <Counter name="señor"/> </div> ); }}
![Page 43: Integrando React.js en aplicaciones Symfony (deSymfony 2016)](https://reader033.fdocumento.com/reader033/viewer/2022061610/58720ee81a28ab176b8b8217/html5/thumbnails/43.jpg)
Pro tip: componentes sin estado
const Saludador = (props) => { <div> <div>Hola {props.name}</div> </div>}
![Page 44: Integrando React.js en aplicaciones Symfony (deSymfony 2016)](https://reader033.fdocumento.com/reader033/viewer/2022061610/58720ee81a28ab176b8b8217/html5/thumbnails/44.jpg)
Todo depende del estado, por tanto:
![Page 45: Integrando React.js en aplicaciones Symfony (deSymfony 2016)](https://reader033.fdocumento.com/reader033/viewer/2022061610/58720ee81a28ab176b8b8217/html5/thumbnails/45.jpg)
Todo depende del estado, por tanto:
•Podemos reproducir estados,
![Page 46: Integrando React.js en aplicaciones Symfony (deSymfony 2016)](https://reader033.fdocumento.com/reader033/viewer/2022061610/58720ee81a28ab176b8b8217/html5/thumbnails/46.jpg)
Todo depende del estado, por tanto:
•Podemos reproducir estados,•rebobinar,
![Page 47: Integrando React.js en aplicaciones Symfony (deSymfony 2016)](https://reader033.fdocumento.com/reader033/viewer/2022061610/58720ee81a28ab176b8b8217/html5/thumbnails/47.jpg)
Todo depende del estado, por tanto:
•Podemos reproducir estados,•rebobinar,•loguear cambios de estado,
![Page 48: Integrando React.js en aplicaciones Symfony (deSymfony 2016)](https://reader033.fdocumento.com/reader033/viewer/2022061610/58720ee81a28ab176b8b8217/html5/thumbnails/48.jpg)
Todo depende del estado, por tanto:
•Podemos reproducir estados,•rebobinar,•loguear cambios de estado,•hacer álbum de estilo
![Page 49: Integrando React.js en aplicaciones Symfony (deSymfony 2016)](https://reader033.fdocumento.com/reader033/viewer/2022061610/58720ee81a28ab176b8b8217/html5/thumbnails/49.jpg)
Todo depende del estado, por tanto:
•Podemos reproducir estados,•rebobinar,•loguear cambios de estado,•hacer álbum de estilo•…
![Page 50: Integrando React.js en aplicaciones Symfony (deSymfony 2016)](https://reader033.fdocumento.com/reader033/viewer/2022061610/58720ee81a28ab176b8b8217/html5/thumbnails/50.jpg)
Learn once, write everywhere
![Page 51: Integrando React.js en aplicaciones Symfony (deSymfony 2016)](https://reader033.fdocumento.com/reader033/viewer/2022061610/58720ee81a28ab176b8b8217/html5/thumbnails/51.jpg)
¿Y si en lugar de algo así…
render() { return ( <div className="App"> <button onClick={this.tick.bind(this)}>Clícame!</button> <span>Clicks: {this.state.count}</span> </div> ); }
![Page 52: Integrando React.js en aplicaciones Symfony (deSymfony 2016)](https://reader033.fdocumento.com/reader033/viewer/2022061610/58720ee81a28ab176b8b8217/html5/thumbnails/52.jpg)
…tenemos algo así?render () { return ( <View> <ListView dataSource={dataSource} renderRow={(rowData) => <TouchableOpacity > <View> <Text>{rowData.name}</Text> <View> <SwitchIOS onValueChange={(value) => this.setMissing(item, value)} value={item.missing} /> </View> </View> </TouchableOpacity> } /> </View> );}
![Page 53: Integrando React.js en aplicaciones Symfony (deSymfony 2016)](https://reader033.fdocumento.com/reader033/viewer/2022061610/58720ee81a28ab176b8b8217/html5/thumbnails/53.jpg)
…tenemos algo así?render () { return ( <View> <ListView dataSource={dataSource} renderRow={(rowData) => <TouchableOpacity > <View> <Text>{rowData.name}</Text> <View> <SwitchIOS onValueChange={(value) => this.setMissing(item, value)} value={item.missing} /> </View> </View> </TouchableOpacity> } /> </View> );}
React Native
![Page 54: Integrando React.js en aplicaciones Symfony (deSymfony 2016)](https://reader033.fdocumento.com/reader033/viewer/2022061610/58720ee81a28ab176b8b8217/html5/thumbnails/54.jpg)
React Targets
• Web - react-dom • Mobile - React Native • Gl shaders - gl-react • Canvas - react-canvas • Terminal - react-blessed
![Page 55: Integrando React.js en aplicaciones Symfony (deSymfony 2016)](https://reader033.fdocumento.com/reader033/viewer/2022061610/58720ee81a28ab176b8b8217/html5/thumbnails/55.jpg)
react-blessed (terminal)
![Page 56: Integrando React.js en aplicaciones Symfony (deSymfony 2016)](https://reader033.fdocumento.com/reader033/viewer/2022061610/58720ee81a28ab176b8b8217/html5/thumbnails/56.jpg)
Setup
![Page 57: Integrando React.js en aplicaciones Symfony (deSymfony 2016)](https://reader033.fdocumento.com/reader033/viewer/2022061610/58720ee81a28ab176b8b8217/html5/thumbnails/57.jpg)
¿Assetic?
Setup recomendado
![Page 58: Integrando React.js en aplicaciones Symfony (deSymfony 2016)](https://reader033.fdocumento.com/reader033/viewer/2022061610/58720ee81a28ab176b8b8217/html5/thumbnails/58.jpg)
Setup recomendado
![Page 59: Integrando React.js en aplicaciones Symfony (deSymfony 2016)](https://reader033.fdocumento.com/reader033/viewer/2022061610/58720ee81a28ab176b8b8217/html5/thumbnails/59.jpg)
WebpackPros
![Page 60: Integrando React.js en aplicaciones Symfony (deSymfony 2016)](https://reader033.fdocumento.com/reader033/viewer/2022061610/58720ee81a28ab176b8b8217/html5/thumbnails/60.jpg)
Webpack
• Gestiona dependencias por nosotros.Pros
![Page 61: Integrando React.js en aplicaciones Symfony (deSymfony 2016)](https://reader033.fdocumento.com/reader033/viewer/2022061610/58720ee81a28ab176b8b8217/html5/thumbnails/61.jpg)
Webpack
• Gestiona dependencias por nosotros.• Permite varios entornos: producción, desarrollo, ….
Pros
![Page 62: Integrando React.js en aplicaciones Symfony (deSymfony 2016)](https://reader033.fdocumento.com/reader033/viewer/2022061610/58720ee81a28ab176b8b8217/html5/thumbnails/62.jpg)
Webpack
• Gestiona dependencias por nosotros.• Permite varios entornos: producción, desarrollo, ….• Recarga automática de página (e incluso hot reload).
Pros
![Page 63: Integrando React.js en aplicaciones Symfony (deSymfony 2016)](https://reader033.fdocumento.com/reader033/viewer/2022061610/58720ee81a28ab176b8b8217/html5/thumbnails/63.jpg)
Webpack
• Gestiona dependencias por nosotros.• Permite varios entornos: producción, desarrollo, ….• Recarga automática de página (e incluso hot reload).• Uso de preprocesadores/“transpiladores”, como Babel.
Pros
![Page 64: Integrando React.js en aplicaciones Symfony (deSymfony 2016)](https://reader033.fdocumento.com/reader033/viewer/2022061610/58720ee81a28ab176b8b8217/html5/thumbnails/64.jpg)
Webpack
• Gestiona dependencias por nosotros.• Permite varios entornos: producción, desarrollo, ….• Recarga automática de página (e incluso hot reload).• Uso de preprocesadores/“transpiladores”, como Babel.• Los programadores de frontend no nos arquearán la ceja.
Pros
![Page 65: Integrando React.js en aplicaciones Symfony (deSymfony 2016)](https://reader033.fdocumento.com/reader033/viewer/2022061610/58720ee81a28ab176b8b8217/html5/thumbnails/65.jpg)
Webpack
• Gestiona dependencias por nosotros.• Permite varios entornos: producción, desarrollo, ….• Recarga automática de página (e incluso hot reload).• Uso de preprocesadores/“transpiladores”, como Babel.• Los programadores de frontend no nos arquearán la ceja.
Pros
Contras
![Page 66: Integrando React.js en aplicaciones Symfony (deSymfony 2016)](https://reader033.fdocumento.com/reader033/viewer/2022061610/58720ee81a28ab176b8b8217/html5/thumbnails/66.jpg)
Webpack
• Gestiona dependencias por nosotros.• Permite varios entornos: producción, desarrollo, ….• Recarga automática de página (e incluso hot reload).• Uso de preprocesadores/“transpiladores”, como Babel.• Los programadores de frontend no nos arquearán la ceja.
Pros
Contras• Tiene su curva de aprendizaje.
![Page 67: Integrando React.js en aplicaciones Symfony (deSymfony 2016)](https://reader033.fdocumento.com/reader033/viewer/2022061610/58720ee81a28ab176b8b8217/html5/thumbnails/67.jpg)
Webpack
• Gestiona dependencias por nosotros.• Permite varios entornos: producción, desarrollo, ….• Recarga automática de página (e incluso hot reload).• Uso de preprocesadores/“transpiladores”, como Babel.• Los programadores de frontend no nos arquearán la ceja.
Pros
Contras• Tiene su curva de aprendizaje.
Ejemplo completo: https://github.com/Limenius/symfony-react-sandbox
![Page 68: Integrando React.js en aplicaciones Symfony (deSymfony 2016)](https://reader033.fdocumento.com/reader033/viewer/2022061610/58720ee81a28ab176b8b8217/html5/thumbnails/68.jpg)
Inserción
<div id="react-placeholder"></div>
import ReactDOM from 'react-dom';
ReactDOM.render( <Counter name="amigo">, document.getElementById('react-placeholder'));
HTML
JavaScript
![Page 69: Integrando React.js en aplicaciones Symfony (deSymfony 2016)](https://reader033.fdocumento.com/reader033/viewer/2022061610/58720ee81a28ab176b8b8217/html5/thumbnails/69.jpg)
Integración con Symfony https://github.com/Limenius/ReactBundle
![Page 71: Integrando React.js en aplicaciones Symfony (deSymfony 2016)](https://reader033.fdocumento.com/reader033/viewer/2022061610/58720ee81a28ab176b8b8217/html5/thumbnails/71.jpg)
ReactBundle
{{ react_component('RecipesApp', {'props': props}) }}
import ReactOnRails from 'react-on-rails';import RecipesApp from './RecipesAppServer';
ReactOnRails.register({ RecipesApp });
Twig:
JavaScript:
![Page 72: Integrando React.js en aplicaciones Symfony (deSymfony 2016)](https://reader033.fdocumento.com/reader033/viewer/2022061610/58720ee81a28ab176b8b8217/html5/thumbnails/72.jpg)
ReactBundle
{{ react_component('RecipesApp', {'props': props}) }}
import ReactOnRails from 'react-on-rails';import RecipesApp from './RecipesAppServer';
ReactOnRails.register({ RecipesApp });
Twig:
JavaScript:
![Page 73: Integrando React.js en aplicaciones Symfony (deSymfony 2016)](https://reader033.fdocumento.com/reader033/viewer/2022061610/58720ee81a28ab176b8b8217/html5/thumbnails/73.jpg)
ReactBundle
{{ react_component('RecipesApp', {'props': props}) }}
import ReactOnRails from 'react-on-rails';import RecipesApp from './RecipesAppServer';
ReactOnRails.register({ RecipesApp });
Twig:
JavaScript:
![Page 74: Integrando React.js en aplicaciones Symfony (deSymfony 2016)](https://reader033.fdocumento.com/reader033/viewer/2022061610/58720ee81a28ab176b8b8217/html5/thumbnails/74.jpg)
ReactBundle
{{ react_component('RecipesApp', {'props': props}) }}
import ReactOnRails from 'react-on-rails';import RecipesApp from './RecipesAppServer';
ReactOnRails.register({ RecipesApp });
Twig:
JavaScript:
<div class="js-react-on-rails-component" style="display:none" data-component-name=“RecipesApp” data-props=“[mi Array en JSON]" data-trace=“false" data-dom-id=“sfreact-57d05640f2f1a”></div>
HTML generado:
![Page 75: Integrando React.js en aplicaciones Symfony (deSymfony 2016)](https://reader033.fdocumento.com/reader033/viewer/2022061610/58720ee81a28ab176b8b8217/html5/thumbnails/75.jpg)
Aplicaciones universales
![Page 76: Integrando React.js en aplicaciones Symfony (deSymfony 2016)](https://reader033.fdocumento.com/reader033/viewer/2022061610/58720ee81a28ab176b8b8217/html5/thumbnails/76.jpg)
![Page 77: Integrando React.js en aplicaciones Symfony (deSymfony 2016)](https://reader033.fdocumento.com/reader033/viewer/2022061610/58720ee81a28ab176b8b8217/html5/thumbnails/77.jpg)
Dame un estado y una función render() que dependa de él, y olvídate de cómo y cuándo pinto.
La premisa fundamental
![Page 78: Integrando React.js en aplicaciones Symfony (deSymfony 2016)](https://reader033.fdocumento.com/reader033/viewer/2022061610/58720ee81a28ab176b8b8217/html5/thumbnails/78.jpg)
Dame un estado y una función render() que dependa de él, y olvídate de cómo y cuándo pinto.
La premisa fundamental
Podemos renderizar componentes desde el servidor.
![Page 79: Integrando React.js en aplicaciones Symfony (deSymfony 2016)](https://reader033.fdocumento.com/reader033/viewer/2022061610/58720ee81a28ab176b8b8217/html5/thumbnails/79.jpg)
Dame un estado y una función render() que dependa de él, y olvídate de cómo y cuándo pinto.
La premisa fundamental
Podemos renderizar componentes desde el servidor.
• SEO friendly.
![Page 80: Integrando React.js en aplicaciones Symfony (deSymfony 2016)](https://reader033.fdocumento.com/reader033/viewer/2022061610/58720ee81a28ab176b8b8217/html5/thumbnails/80.jpg)
Dame un estado y una función render() que dependa de él, y olvídate de cómo y cuándo pinto.
La premisa fundamental
Podemos renderizar componentes desde el servidor.
• SEO friendly.• Carga de página más rápida.
![Page 81: Integrando React.js en aplicaciones Symfony (deSymfony 2016)](https://reader033.fdocumento.com/reader033/viewer/2022061610/58720ee81a28ab176b8b8217/html5/thumbnails/81.jpg)
Dame un estado y una función render() que dependa de él, y olvídate de cómo y cuándo pinto.
La premisa fundamental
Podemos renderizar componentes desde el servidor.
• SEO friendly.• Carga de página más rápida.• Podemos cachear.
![Page 82: Integrando React.js en aplicaciones Symfony (deSymfony 2016)](https://reader033.fdocumento.com/reader033/viewer/2022061610/58720ee81a28ab176b8b8217/html5/thumbnails/82.jpg)
Client-side
{{ react_component('RecipesApp', {'props': props, 'rendering': 'client-side'}}) }}
TWIG
![Page 83: Integrando React.js en aplicaciones Symfony (deSymfony 2016)](https://reader033.fdocumento.com/reader033/viewer/2022061610/58720ee81a28ab176b8b8217/html5/thumbnails/83.jpg)
Client-side
{{ react_component('RecipesApp', {'props': props, 'rendering': 'client-side'}}) }}
TWIG
![Page 84: Integrando React.js en aplicaciones Symfony (deSymfony 2016)](https://reader033.fdocumento.com/reader033/viewer/2022061610/58720ee81a28ab176b8b8217/html5/thumbnails/84.jpg)
Client-side
{{ react_component('RecipesApp', {'props': props, 'rendering': 'client-side'}}) }}
TWIG
<div class="js-react-on-rails-component" style="display:none" data-component-name=“RecipesApp” data-props=“…” data-dom-id=“sfreact-57d05640f2f1a”></div>
HTML que devuelve el servidor
![Page 85: Integrando React.js en aplicaciones Symfony (deSymfony 2016)](https://reader033.fdocumento.com/reader033/viewer/2022061610/58720ee81a28ab176b8b8217/html5/thumbnails/85.jpg)
Client-side
{{ react_component('RecipesApp', {'props': props, 'rendering': 'client-side'}}) }}
TWIG
<div class="js-react-on-rails-component" style="display:none" data-component-name=“RecipesApp” data-props=“…” data-dom-id=“sfreact-57d05640f2f1a”></div>
HTML que devuelve el servidor
Generado en el navegador<div id="sfreact-57d05640f2f1a"><div data-reactroot="" data-reactid="1" data-react-checksum="2107256409"><ol class="breadcrumb" data-reactid="2"><li class="active" data-reactid=“3">Recipes</li>……</div>
![Page 86: Integrando React.js en aplicaciones Symfony (deSymfony 2016)](https://reader033.fdocumento.com/reader033/viewer/2022061610/58720ee81a28ab176b8b8217/html5/thumbnails/86.jpg)
Client-side y server-side
{{ react_component('RecipesApp', {'props': props, 'rendering': 'both'}}) }}
TWIG
![Page 87: Integrando React.js en aplicaciones Symfony (deSymfony 2016)](https://reader033.fdocumento.com/reader033/viewer/2022061610/58720ee81a28ab176b8b8217/html5/thumbnails/87.jpg)
Client-side y server-side
{{ react_component('RecipesApp', {'props': props, 'rendering': 'both'}}) }}
TWIG
![Page 88: Integrando React.js en aplicaciones Symfony (deSymfony 2016)](https://reader033.fdocumento.com/reader033/viewer/2022061610/58720ee81a28ab176b8b8217/html5/thumbnails/88.jpg)
Client-side y server-side
{{ react_component('RecipesApp', {'props': props, 'rendering': 'both'}}) }}
TWIG
HTML que devuelve el servidor<div id="sfreact-57d05640f2f1a"><div data-reactroot="" data-reactid="1" data-react-checksum="2107256409"><ol class="breadcrumb" data-reactid="2"><li class="active" data-reactid=“3">Recipes</li>……</div>
![Page 89: Integrando React.js en aplicaciones Symfony (deSymfony 2016)](https://reader033.fdocumento.com/reader033/viewer/2022061610/58720ee81a28ab176b8b8217/html5/thumbnails/89.jpg)
Client-side y server-side
{{ react_component('RecipesApp', {'props': props, 'rendering': 'both'}}) }}
TWIG
HTML que devuelve el servidor<div id="sfreact-57d05640f2f1a"><div data-reactroot="" data-reactid="1" data-react-checksum="2107256409"><ol class="breadcrumb" data-reactid="2"><li class="active" data-reactid=“3">Recipes</li>……</div>
Y React en el navegador toma el control al evaluar el código
![Page 90: Integrando React.js en aplicaciones Symfony (deSymfony 2016)](https://reader033.fdocumento.com/reader033/viewer/2022061610/58720ee81a28ab176b8b8217/html5/thumbnails/90.jpg)
Aplicaciones universales: Opciones
![Page 91: Integrando React.js en aplicaciones Symfony (deSymfony 2016)](https://reader033.fdocumento.com/reader033/viewer/2022061610/58720ee81a28ab176b8b8217/html5/thumbnails/91.jpg)
Opción 1: llamar a subproceso node.jsLlamamos a node.js con el componente Process de Symfony
* Cómodo (si tenemos node.js instalado).
* Lento.
Librería: https://github.com/nacmartin/phpexecjs
![Page 92: Integrando React.js en aplicaciones Symfony (deSymfony 2016)](https://reader033.fdocumento.com/reader033/viewer/2022061610/58720ee81a28ab176b8b8217/html5/thumbnails/92.jpg)
Opción 2: v8jsUsamos la extensión de PHP v8js
* Cómodo (aunque puede que haya que compilar la extensión y v8).
* Lento por ahora, potencialmente podríamos tener v8 precargada usando php-pm.
Librería: https://github.com/nacmartin/phpexecjs
![Page 93: Integrando React.js en aplicaciones Symfony (deSymfony 2016)](https://reader033.fdocumento.com/reader033/viewer/2022061610/58720ee81a28ab176b8b8217/html5/thumbnails/93.jpg)
Configuración Opciones 1 y 2
limenius_react: serverside_rendering: mode: "phpexecjs"
phpexecjs detecta si tenemos la extensión v8js, y si no llama a node.js
config.yml:
![Page 94: Integrando React.js en aplicaciones Symfony (deSymfony 2016)](https://reader033.fdocumento.com/reader033/viewer/2022061610/58720ee81a28ab176b8b8217/html5/thumbnails/94.jpg)
Opción 3: Servidor externoTenemos un servidor node.js “tonto” que nos renderiza React.
Es un servidor de <100 líneas, que es independiente de nuestra lógica.
* “Incómodo” (hay que mantener el servidor node.js corriendo, que tampoco es para morirse).
* Rápido.
Ver ejemplo en https://github.com/Limenius/symfony-react-sandbox
![Page 95: Integrando React.js en aplicaciones Symfony (deSymfony 2016)](https://reader033.fdocumento.com/reader033/viewer/2022061610/58720ee81a28ab176b8b8217/html5/thumbnails/95.jpg)
Configuración Opción 3
limenius_react: serverside_rendering: mode: “external” server-socket-path: “../tal_y_tal/node.sock”
config.yml:
![Page 96: Integrando React.js en aplicaciones Symfony (deSymfony 2016)](https://reader033.fdocumento.com/reader033/viewer/2022061610/58720ee81a28ab176b8b8217/html5/thumbnails/96.jpg)
Lo mejor de los dos mundosEn desarrollo usar llamada a node.js o v8js con phpexecjs.
En producción tener un servidor externo.
Si podemos cachear, menos problema.
![Page 97: Integrando React.js en aplicaciones Symfony (deSymfony 2016)](https://reader033.fdocumento.com/reader033/viewer/2022061610/58720ee81a28ab176b8b8217/html5/thumbnails/97.jpg)
Es decir:
limenius_react: serverside_rendering: mode: “external” server-socket-path: “../tal_y_tal/node.sock”
config.yml:
limenius_react: serverside_rendering: mode: "phpexecjs"
config_dev.yml:
![Page 98: Integrando React.js en aplicaciones Symfony (deSymfony 2016)](https://reader033.fdocumento.com/reader033/viewer/2022061610/58720ee81a28ab176b8b8217/html5/thumbnails/98.jpg)
¿Vale la pena una app universal?
![Page 99: Integrando React.js en aplicaciones Symfony (deSymfony 2016)](https://reader033.fdocumento.com/reader033/viewer/2022061610/58720ee81a28ab176b8b8217/html5/thumbnails/99.jpg)
¿Vale la pena una app universal?
En ocasiones sí, pero introduce complejidad.
![Page 100: Integrando React.js en aplicaciones Symfony (deSymfony 2016)](https://reader033.fdocumento.com/reader033/viewer/2022061610/58720ee81a28ab176b8b8217/html5/thumbnails/100.jpg)
Soporte para Redux (+brevísima introducción a Redux)
![Page 101: Integrando React.js en aplicaciones Symfony (deSymfony 2016)](https://reader033.fdocumento.com/reader033/viewer/2022061610/58720ee81a28ab176b8b8217/html5/thumbnails/101.jpg)
Redux: una cuestión de estado
guardar
Tu nombre: Juan
Hola, Juan
Cosas de Juan:
![Page 102: Integrando React.js en aplicaciones Symfony (deSymfony 2016)](https://reader033.fdocumento.com/reader033/viewer/2022061610/58720ee81a28ab176b8b8217/html5/thumbnails/102.jpg)
Redux: una cuestión de estado
guardar
Tu nombre: Juan
Hola, Juan
Cosas de Juan:
![Page 103: Integrando React.js en aplicaciones Symfony (deSymfony 2016)](https://reader033.fdocumento.com/reader033/viewer/2022061610/58720ee81a28ab176b8b8217/html5/thumbnails/103.jpg)
Redux: una cuestión de estado
guardar
Tu nombre: Juan
Hola, Juan
Cosas de Juan:
state.name
callback para cambiarlo
![Page 104: Integrando React.js en aplicaciones Symfony (deSymfony 2016)](https://reader033.fdocumento.com/reader033/viewer/2022061610/58720ee81a28ab176b8b8217/html5/thumbnails/104.jpg)
dispatch(changeName(‘Juan'));
Componente
![Page 105: Integrando React.js en aplicaciones Symfony (deSymfony 2016)](https://reader033.fdocumento.com/reader033/viewer/2022061610/58720ee81a28ab176b8b8217/html5/thumbnails/105.jpg)
dispatch(changeName(‘Juan'));
Componente
changeName = (name) => { return { type: ‘CHANGE_NAME', name }}
Action
![Page 106: Integrando React.js en aplicaciones Symfony (deSymfony 2016)](https://reader033.fdocumento.com/reader033/viewer/2022061610/58720ee81a28ab176b8b8217/html5/thumbnails/106.jpg)
dispatch(changeName(‘Juan'));
Componente
changeName = (name) => { return { type: ‘CHANGE_NAME', name }}
Action
const todo = (state = {name: null}, action) => { switch (action.type) { case 'CHANGE_USER': return { name: action.name } }}
Reducer
![Page 107: Integrando React.js en aplicaciones Symfony (deSymfony 2016)](https://reader033.fdocumento.com/reader033/viewer/2022061610/58720ee81a28ab176b8b8217/html5/thumbnails/107.jpg)
dispatch(changeName(‘Juan'));
Componente
changeName = (name) => { return { type: ‘CHANGE_NAME', name }}
Action
const todo = (state = {name: null}, action) => { switch (action.type) { case 'CHANGE_USER': return { name: action.name } }}
Reducer
Store
![Page 108: Integrando React.js en aplicaciones Symfony (deSymfony 2016)](https://reader033.fdocumento.com/reader033/viewer/2022061610/58720ee81a28ab176b8b8217/html5/thumbnails/108.jpg)
this.props.name == ‘Juan';dispatch(changeName(‘Juan'));
Componente
changeName = (name) => { return { type: ‘CHANGE_NAME', name }}
Action
const todo = (state = {name: null}, action) => { switch (action.type) { case 'CHANGE_USER': return { name: action.name } }}
Reducer
Store
![Page 109: Integrando React.js en aplicaciones Symfony (deSymfony 2016)](https://reader033.fdocumento.com/reader033/viewer/2022061610/58720ee81a28ab176b8b8217/html5/thumbnails/109.jpg)
Redux en ReactBundle
Ver ejemplo en https://github.com/Limenius/symfony-react-sandbox
import ReactOnRails from 'react-on-rails';import RecipesApp from './RecipesAppClient';import recipesStore from '../store/recipesStore';
ReactOnRails.registerStore({recipesStore})ReactOnRails.register({ RecipesApp });
Twig:
JavaScript:
{{ redux_store('recipesStore', props) }}{{ react_component('RecipesApp') }}
![Page 110: Integrando React.js en aplicaciones Symfony (deSymfony 2016)](https://reader033.fdocumento.com/reader033/viewer/2022061610/58720ee81a28ab176b8b8217/html5/thumbnails/110.jpg)
Redux en ReactBundle
Ver ejemplo en https://github.com/Limenius/symfony-react-sandbox
import ReactOnRails from 'react-on-rails';import RecipesApp from './RecipesAppClient';import recipesStore from '../store/recipesStore';
ReactOnRails.registerStore({recipesStore})ReactOnRails.register({ RecipesApp });
Twig:
JavaScript:
{{ redux_store('recipesStore', props) }}{{ react_component('RecipesApp') }}{{ react_component('OtroComponente') }}
![Page 111: Integrando React.js en aplicaciones Symfony (deSymfony 2016)](https://reader033.fdocumento.com/reader033/viewer/2022061610/58720ee81a28ab176b8b8217/html5/thumbnails/111.jpg)
Compartir store entre componentes
![Page 112: Integrando React.js en aplicaciones Symfony (deSymfony 2016)](https://reader033.fdocumento.com/reader033/viewer/2022061610/58720ee81a28ab176b8b8217/html5/thumbnails/112.jpg)
Compartir store entre componentesReact
ReactReact
Twig
Twig
React
Al compartir store comparten estado
Twig
![Page 113: Integrando React.js en aplicaciones Symfony (deSymfony 2016)](https://reader033.fdocumento.com/reader033/viewer/2022061610/58720ee81a28ab176b8b8217/html5/thumbnails/113.jpg)
Formularios, un caso especial
![Page 114: Integrando React.js en aplicaciones Symfony (deSymfony 2016)](https://reader033.fdocumento.com/reader033/viewer/2022061610/58720ee81a28ab176b8b8217/html5/thumbnails/114.jpg)
Formularios muy dinámicos•Dentro de aplicaciones React.
•Formularios importantísimos en los que un detalle de usabilidad vale mucho dinero.
•Formularios muy específicos.
•Formularios muy dinámicos que no cansen (ver typeform por ejemplo).
![Page 115: Integrando React.js en aplicaciones Symfony (deSymfony 2016)](https://reader033.fdocumento.com/reader033/viewer/2022061610/58720ee81a28ab176b8b8217/html5/thumbnails/115.jpg)
![Page 116: Integrando React.js en aplicaciones Symfony (deSymfony 2016)](https://reader033.fdocumento.com/reader033/viewer/2022061610/58720ee81a28ab176b8b8217/html5/thumbnails/116.jpg)
El problema
![Page 117: Integrando React.js en aplicaciones Symfony (deSymfony 2016)](https://reader033.fdocumento.com/reader033/viewer/2022061610/58720ee81a28ab176b8b8217/html5/thumbnails/117.jpg)
Supongamos un form así
public function buildForm(FormBuilderInterface $builder, array $options){ $builder ->add('country', ChoiceType::class, [ 'choices' => [ 'España' => 'es', 'Portugal' => 'pt', ] ]) ->add('addresses', CollectionType::class, ...);};
![Page 118: Integrando React.js en aplicaciones Symfony (deSymfony 2016)](https://reader033.fdocumento.com/reader033/viewer/2022061610/58720ee81a28ab176b8b8217/html5/thumbnails/118.jpg)
Forms en HTML
$form->createView();
state.usuario
![Page 119: Integrando React.js en aplicaciones Symfony (deSymfony 2016)](https://reader033.fdocumento.com/reader033/viewer/2022061610/58720ee81a28ab176b8b8217/html5/thumbnails/119.jpg)
Forms en HTML
$form->createView();
state.usuario
![Page 120: Integrando React.js en aplicaciones Symfony (deSymfony 2016)](https://reader033.fdocumento.com/reader033/viewer/2022061610/58720ee81a28ab176b8b8217/html5/thumbnails/120.jpg)
Forms en HTML
$form->createView();
submit
país: España
EspañaPortugal
direcciones:
C\ tal-+state.usuario
![Page 121: Integrando React.js en aplicaciones Symfony (deSymfony 2016)](https://reader033.fdocumento.com/reader033/viewer/2022061610/58720ee81a28ab176b8b8217/html5/thumbnails/121.jpg)
Forms en HTML
$form->createView();
submit
país: España
EspañaPortugal
direcciones:
C\ tal-+state.usuario
![Page 122: Integrando React.js en aplicaciones Symfony (deSymfony 2016)](https://reader033.fdocumento.com/reader033/viewer/2022061610/58720ee81a28ab176b8b8217/html5/thumbnails/122.jpg)
Forms en HTML
$form->createView();
submit
país: España
EspañaPortugal
direcciones:
C\ tal-+state.usuario
POST bien formadito con country:’es’
y no ‘España’, ‘espana', ‘spain', ‘0’…
![Page 123: Integrando React.js en aplicaciones Symfony (deSymfony 2016)](https://reader033.fdocumento.com/reader033/viewer/2022061610/58720ee81a28ab176b8b8217/html5/thumbnails/123.jpg)
Forms en HTML
$form->createView();
$form->submit($request);
submit
país: España
EspañaPortugal
direcciones:
C\ tal-+state.usuario
POST bien formadito con country:’es’
y no ‘España’, ‘espana', ‘spain', ‘0’…
![Page 124: Integrando React.js en aplicaciones Symfony (deSymfony 2016)](https://reader033.fdocumento.com/reader033/viewer/2022061610/58720ee81a28ab176b8b8217/html5/thumbnails/124.jpg)
Forms en API
$form;
state.usuario
![Page 125: Integrando React.js en aplicaciones Symfony (deSymfony 2016)](https://reader033.fdocumento.com/reader033/viewer/2022061610/58720ee81a28ab176b8b8217/html5/thumbnails/125.jpg)
Forms en API
$form;
submit
país: España
EspañaPortugal
direcciones:
C\ tal-+state.usuario
✘
![Page 126: Integrando React.js en aplicaciones Symfony (deSymfony 2016)](https://reader033.fdocumento.com/reader033/viewer/2022061610/58720ee81a28ab176b8b8217/html5/thumbnails/126.jpg)
Forms en API
$form;
submit
país: España
EspañaPortugal
direcciones:
C\ tal-+state.usuario
✘¿Cómo sabemos los campos,
o los choices? ¡A documentar! :(
![Page 127: Integrando React.js en aplicaciones Symfony (deSymfony 2016)](https://reader033.fdocumento.com/reader033/viewer/2022061610/58720ee81a28ab176b8b8217/html5/thumbnails/127.jpg)
Forms en API
$form;
$form->submit($request);
submit
país: España
EspañaPortugal
direcciones:
C\ tal-+state.usuario
POST “voy a tener suerte”
✘¿Cómo sabemos los campos,
o los choices? ¡A documentar! :(
![Page 128: Integrando React.js en aplicaciones Symfony (deSymfony 2016)](https://reader033.fdocumento.com/reader033/viewer/2022061610/58720ee81a28ab176b8b8217/html5/thumbnails/128.jpg)
Forms en API
$form;
$form->submit($request);
submit
país: España
EspañaPortugal
direcciones:
C\ tal-+state.usuario
POST “voy a tener suerte”
✘¿Cómo sabemos los campos,
o los choices? ¡A documentar! :(
This form should not contain extra fields!!1
![Page 129: Integrando React.js en aplicaciones Symfony (deSymfony 2016)](https://reader033.fdocumento.com/reader033/viewer/2022061610/58720ee81a28ab176b8b8217/html5/thumbnails/129.jpg)
Forms en API
$form;
$form->submit($request);
submit
país: España
EspañaPortugal
direcciones:
C\ tal-+state.usuario
POST “voy a tener suerte”
✘¿Cómo sabemos los campos,
o los choices? ¡A documentar! :(
This form should not contain extra fields!!1The value you selected is not a valid choice!!
![Page 130: Integrando React.js en aplicaciones Symfony (deSymfony 2016)](https://reader033.fdocumento.com/reader033/viewer/2022061610/58720ee81a28ab176b8b8217/html5/thumbnails/130.jpg)
Forms en API
$form;
$form->submit($request);
submit
país: España
EspañaPortugal
direcciones:
C\ tal-+state.usuario
POST “voy a tener suerte”
✘¿Cómo sabemos los campos,
o los choices? ¡A documentar! :(
This form should not contain extra fields!!1The value you selected is not a valid choice!!One or more of the given values is invalid!! :D
![Page 131: Integrando React.js en aplicaciones Symfony (deSymfony 2016)](https://reader033.fdocumento.com/reader033/viewer/2022061610/58720ee81a28ab176b8b8217/html5/thumbnails/131.jpg)
Forms en API
$form;
$form->submit($request);
submit
país: España
EspañaPortugal
direcciones:
C\ tal-+state.usuario
POST “voy a tener suerte”
✘¿Cómo sabemos los campos,
o los choices? ¡A documentar! :(
This form should not contain extra fields!!1The value you selected is not a valid choice!!One or more of the given values is invalid!! :DMUHAHAHAHAHA!!!!!
![Page 132: Integrando React.js en aplicaciones Symfony (deSymfony 2016)](https://reader033.fdocumento.com/reader033/viewer/2022061610/58720ee81a28ab176b8b8217/html5/thumbnails/132.jpg)
![Page 133: Integrando React.js en aplicaciones Symfony (deSymfony 2016)](https://reader033.fdocumento.com/reader033/viewer/2022061610/58720ee81a28ab176b8b8217/html5/thumbnails/133.jpg)
![Page 134: Integrando React.js en aplicaciones Symfony (deSymfony 2016)](https://reader033.fdocumento.com/reader033/viewer/2022061610/58720ee81a28ab176b8b8217/html5/thumbnails/134.jpg)
Definir (y mantener) por triplicado
Form SF API docs Form Cliente
:(
¿Cuántos programadores hacen falta para hacer un formulario?
![Page 135: Integrando React.js en aplicaciones Symfony (deSymfony 2016)](https://reader033.fdocumento.com/reader033/viewer/2022061610/58720ee81a28ab176b8b8217/html5/thumbnails/135.jpg)
Caso: Wizard complejo
![Page 136: Integrando React.js en aplicaciones Symfony (deSymfony 2016)](https://reader033.fdocumento.com/reader033/viewer/2022061610/58720ee81a28ab176b8b8217/html5/thumbnails/136.jpg)
Caso: Wizard complejo
![Page 137: Integrando React.js en aplicaciones Symfony (deSymfony 2016)](https://reader033.fdocumento.com/reader033/viewer/2022061610/58720ee81a28ab176b8b8217/html5/thumbnails/137.jpg)
Caso: Wizard complejo
![Page 138: Integrando React.js en aplicaciones Symfony (deSymfony 2016)](https://reader033.fdocumento.com/reader033/viewer/2022061610/58720ee81a28ab176b8b8217/html5/thumbnails/138.jpg)
Lo que necesitamos
$form->createView();
HTML
API$miTransformador->transform($form);
![Page 139: Integrando React.js en aplicaciones Symfony (deSymfony 2016)](https://reader033.fdocumento.com/reader033/viewer/2022061610/58720ee81a28ab176b8b8217/html5/thumbnails/139.jpg)
Lo que necesitamos
$form->createView();
HTML
¡Serializar! Vale, ¿A qué formato?
API$miTransformador->transform($form);
![Page 140: Integrando React.js en aplicaciones Symfony (deSymfony 2016)](https://reader033.fdocumento.com/reader033/viewer/2022061610/58720ee81a28ab176b8b8217/html5/thumbnails/140.jpg)
JSON Schema
![Page 141: Integrando React.js en aplicaciones Symfony (deSymfony 2016)](https://reader033.fdocumento.com/reader033/viewer/2022061610/58720ee81a28ab176b8b8217/html5/thumbnails/141.jpg)
![Page 142: Integrando React.js en aplicaciones Symfony (deSymfony 2016)](https://reader033.fdocumento.com/reader033/viewer/2022061610/58720ee81a28ab176b8b8217/html5/thumbnails/142.jpg)
Qué pinta tiene{ "$schema": "http://json-schema.org/draft-04/schema#", "title": "Product", "description": "A product from Acme's catalog", "type": "object", "properties": { "name": { "description": "Name of the product", "type": "string" }, "price": { "type": "number", "minimum": 0, "exclusiveMinimum": true }, "tags": { "type": "array", "items": { "type": "string" }, "minItems": 1, "uniqueItems": true } }, "required": ["id", "name", "price"]}
definiciones, tipos, reglas de validación :)
Nuevo recurso: mi-api/products/form
![Page 143: Integrando React.js en aplicaciones Symfony (deSymfony 2016)](https://reader033.fdocumento.com/reader033/viewer/2022061610/58720ee81a28ab176b8b8217/html5/thumbnails/143.jpg)
A partir del schema generamos form
![Page 144: Integrando React.js en aplicaciones Symfony (deSymfony 2016)](https://reader033.fdocumento.com/reader033/viewer/2022061610/58720ee81a28ab176b8b8217/html5/thumbnails/144.jpg)
Generadores client-side
• jdorn/json-editor: no React, es un veterano.
• mozilla/react-jsonschema-form: React. creado por un antiguo Symfonero (Niko Perriault).
• limenius/liform-react: React + redux; integrado con redux-form (I ♥ redux-form)
• …
• Crear el nuestro puede ser conveniente.
![Page 145: Integrando React.js en aplicaciones Symfony (deSymfony 2016)](https://reader033.fdocumento.com/reader033/viewer/2022061610/58720ee81a28ab176b8b8217/html5/thumbnails/145.jpg)
Generadores client-side: diferenciasCada uno amplía json-schema a su manera para
especificar detalles UI: Orden de campos, qué widget específico usar, etc.
Si queremos usarlos al máximo hay que generar un json-schema específico para cada uno
(no son totalmente intercambiables).
Ejemplo: usar editor Wysiwyg en un campo texto
![Page 146: Integrando React.js en aplicaciones Symfony (deSymfony 2016)](https://reader033.fdocumento.com/reader033/viewer/2022061610/58720ee81a28ab176b8b8217/html5/thumbnails/146.jpg)
Ejemplo: LiformBundle y liform-react
limenius/LiformBundle: Genera json-schema a partir de formularios Symfony.
limenius/liform-react: Generador de formularios React (con redux-form) a partir de json-schema.
Son Work in progress
![Page 147: Integrando React.js en aplicaciones Symfony (deSymfony 2016)](https://reader033.fdocumento.com/reader033/viewer/2022061610/58720ee81a28ab176b8b8217/html5/thumbnails/147.jpg)
Cómo serializar: resolvers + transformers
$transformer = $resolver->resolve($form);
$jsonSchema = $transformer->transform($form);
Ejemplo de esta técnica: https://github.com/Limenius/LiformBundle
![Page 148: Integrando React.js en aplicaciones Symfony (deSymfony 2016)](https://reader033.fdocumento.com/reader033/viewer/2022061610/58720ee81a28ab176b8b8217/html5/thumbnails/148.jpg)
Resolver
public function resolve(FormInterface $form){ $types = FormUtil::typeAncestry($form);
foreach ($types as $type) { if (isset($this->transformers[$type])) { return $this->transformers[$type]; } }}
Misión: Encuentra el transformer apropiado para el form
![Page 149: Integrando React.js en aplicaciones Symfony (deSymfony 2016)](https://reader033.fdocumento.com/reader033/viewer/2022061610/58720ee81a28ab176b8b8217/html5/thumbnails/149.jpg)
TransformerMisión: Inspecciona el form y crea un array.
Si es compuesto resuelve+transforma los hijos.class IntegerTransformer extends AbstractTransformer{ public function transform(FormInterface $form) { $schema = [ 'type' => 'integer', ]; if ($liform = $form->getConfig()->getOption('liform')) { if ($format = $liform['format']) { $schema['format'] = $format; } } $this->addCommonSpecs($form, $schema);
return $schema; }} protected function addLabel($form, &$schema) { if ($label = $form->getConfig()->getOption('label')) { $schema['title'] = $label; } }
![Page 150: Integrando React.js en aplicaciones Symfony (deSymfony 2016)](https://reader033.fdocumento.com/reader033/viewer/2022061610/58720ee81a28ab176b8b8217/html5/thumbnails/150.jpg)
TransformerRecopila información de cada Form Field.
Podemos sacar mucha información: •Valores por defecto & placeholders. •Atributos del formulario. •Validadores.
![Page 151: Integrando React.js en aplicaciones Symfony (deSymfony 2016)](https://reader033.fdocumento.com/reader033/viewer/2022061610/58720ee81a28ab176b8b8217/html5/thumbnails/151.jpg)
Ejemplo: validación ‘pattern’
protected function addPattern($form, &$schema){ if ($attr = $form->getConfig()->getOption('attr')) { if (isset($attr['pattern'])) { $schema['pattern'] = $attr['pattern']; } }}
![Page 152: Integrando React.js en aplicaciones Symfony (deSymfony 2016)](https://reader033.fdocumento.com/reader033/viewer/2022061610/58720ee81a28ab176b8b8217/html5/thumbnails/152.jpg)
Esta técnica vale también para Angular, Backbone, mobile…
![Page 153: Integrando React.js en aplicaciones Symfony (deSymfony 2016)](https://reader033.fdocumento.com/reader033/viewer/2022061610/58720ee81a28ab176b8b8217/html5/thumbnails/153.jpg)
Repaso:
![Page 154: Integrando React.js en aplicaciones Symfony (deSymfony 2016)](https://reader033.fdocumento.com/reader033/viewer/2022061610/58720ee81a28ab176b8b8217/html5/thumbnails/154.jpg)
Repaso:• Qué es React • Setup • Apps universales (ReactBundle) • Para qué sirve Redux • El problema de los formularios • Cómo aliviarlo con JSON Schema
![Page 155: Integrando React.js en aplicaciones Symfony (deSymfony 2016)](https://reader033.fdocumento.com/reader033/viewer/2022061610/58720ee81a28ab176b8b8217/html5/thumbnails/155.jpg)
MADRID · NOV 27-28 · 2015
¡Gracias!@nacmartin
http://limenius.com Formación, consultoría
y desarrollo de proyectos