Introducción a React.js + técnicas y conceptos útiles, como aplicaciones universales (isomórficas) o cómo usar json schema para facilitarnos la vida al trabajar con formularios.
3. 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
4. Objetivo:
Mostrar cosas que nos
encontramos al usar React desde
Symfony, en tierra de nadie, y que
ninguno de los dos va a
documentar.
14. Opciones:
2: Buscamos en el DOM
dónde insertar, qué
mover, qué eliminar.
La premisa fundamental
1: Repintamos todo. Simple Poco eficiente
15. Opciones:
2: Buscamos en el DOM
dónde insertar, qué
mover, qué eliminar.
La premisa fundamental
1: Repintamos todo. Simple
Complejo
Poco eficiente
16. Opciones:
2: Buscamos en el DOM
dónde insertar, qué
mover, qué eliminar.
La premisa fundamental
1: Repintamos todo. Simple
Muy eficienteComplejo
Poco eficiente
17. 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
18. 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
19. 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.
28. Trabajar con el estado
constructor(props) {
super(props);
this.state = {count: 1};
}
Estado inicial
29. Trabajar con el estado
constructor(props) {
super(props);
this.state = {count: 1};
}
Estado inicial
this.setState({count: this.state.count + 1});
Asignar estado
30. 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
31. render() y JSX
render() {
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.
32. render() y JSX
render() {
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.
33. render() y JSX
render() {
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.
35. Thinking in React
render() {
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
36. Thinking in React
render() {
return (
<div className="App">
<button onClick={this.tick.bind(this)}>Clícame!</button>
<span>Clicks: {this.state.count}</span>
</div>
);
}
Aquí no Ajax
37. Thinking in React
render() {
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
62. Webpack
• Gestiona dependencias por nosotros.
• Permite varios entornos: producción, desarrollo, ….
• Recarga automática de página (e incluso hot reload).
Pros
63. 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
64. 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
65. 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
66. 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.
67. 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
77. 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
78. 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.
79. 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.
80. 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.
81. 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.
88. 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>
89. 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
91. Opción 1: llamar a subproceso node.js
Llamamos a node.js con el componente Process de
Symfony
* Cómodo (si tenemos node.js instalado).
* Lento.
Librería: https://github.com/nacmartin/phpexecjs
92. Opción 2: v8js
Usamos 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
93. 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:
94. Opción 3: Servidor externo
Tenemos 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
96. Lo mejor de los dos mundos
En desarrollo usar llamada a node.js o v8js con
phpexecjs.
En producción tener un servidor externo.
Si podemos cachear, menos problema.
114. 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).
126. Forms en API
$form;
submit
país: España
España
Portugal
direcciones:
C tal-
+state.usuario
✘
¿Cómo sabemos los campos,
o los choices?
¡A documentar! :(
128. Forms en API
$form;
$form->submit($request);
submit
país: España
España
Portugal
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
129. Forms en API
$form;
$form->submit($request);
submit
país: España
España
Portugal
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
The value you selected is not a valid choice!!
130. Forms en API
$form;
$form->submit($request);
submit
país: España
España
Portugal
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
The value you selected is not a valid choice!!One or more of the given values is invalid!! :D
131. Forms en API
$form;
$form->submit($request);
submit
país: España
España
Portugal
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
The value you selected is not a valid choice!!One or more of the given values is invalid!! :DMUHAHAHAHAHA!!!!!
134. Definir (y mantener) por triplicado
Form SF API docs Form Cliente
:(
¿Cuántos programadores hacen falta para hacer un
formulario?
144. 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.
145. Generadores client-side: diferencias
Cada 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
146. 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
147. Cómo serializar: resolvers + transformers
$transformer = $resolver->resolve($form);
$jsonSchema = $transformer->transform($form);
Ejemplo de esta técnica: https://github.com/Limenius/LiformBundle
148. 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
149. Transformer
Misió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;
}
}
150. Transformer
Recopila información de cada Form Field.
Podemos sacar mucha información:
•Valores por defecto & placeholders.
•Atributos del formulario.
•Validadores.
151. Ejemplo: validación ‘pattern’
protected function addPattern($form, &$schema)
{
if ($attr = $form->getConfig()->getOption('attr')) {
if (isset($attr['pattern'])) {
$schema['pattern'] = $attr['pattern'];
}
}
}
154. Repaso:
• Qué es React
• Setup
• Apps universales (ReactBundle)
• Para qué sirve Redux
• El problema de los formularios
• Cómo aliviarlo con JSON Schema
155. MADRID · NOV 27-28 · 2015
¡Gracias!
@nacmartin
nacho@limenius.com
http://limenius.com
Formación, consultoría
y desarrollo de proyectos