-
-
Notifications
You must be signed in to change notification settings - Fork 8
2020_08 Formulario interactivo con react en una aplicación que usa sip
El ejercicio por realizar es agregar un registro a la tabla Sip::Ubicación mediante un formulario. Pero al editar cuando se elija un centro poblado debe mostrar automáticamente el tipo de centro poblado.
Para hacerlo se realizan varias etapas de interconexión entre Rails y React.
Actualice a ruby, rails y node más recients, así como a las gemas más recientes y a los paquetes yarn más recientes y verifique:
bundle update
bundle install
CXX=c++ yarn upgrade
CXX=c++ yarn install
bin/rails webpacker:info
Incluso podría requerir aumentar manualmente la versión de webpacker
y de webpacker-dev-server
en package.json
. En Agosto de 2020 las versiones más recientes disponibles en adJ 6.7a1 son:
$ bin/rails webpacker:info
Ruby: ruby 2.7.1p83 (2020-03-31 revision a0c7c23c9c) [x86_64-openbsd]
Rails: 6.0.3.2
Webpacker: 5.2.1
Node: v12.16.1
Yarn: 1.22.4
@rails/webpacker:
/home/.../miap/
└── @rails/[email protected]
Si durante la instalación con yarn
ocurren errores procure resolverlos antes de continuar, porque aunque el proceso continúe y parezca exitoso, podrían reaparecer posteriormente con errores crípticos como Command webpack not found
Actualice archivos de configuración de webpacker (se recomienda analizar cada diferencia --con d
-- y aplicar cambios a archivos que usted no ha modificado --con y
-- pero no en el caso de archivos que usted ha modificar --con n
-- para dejar el suyo o con m
para mezclar).
CXX=c++ bin/rails webpacker:install
Esta orden entre otras ejecutará bin/rails webpacker:binstubs
y actualizará archivos importantes como babel.config.js
Utilice webpacker para instalar parte de lo necesario para desarrollar en react (entre otras .jsx
en config/webpacker.yml
y paquetes yarn como react
, react-domm
, @babel/preset-react
, prop-types
, babel-plugin-transform-react-remove-prop-types
):
bin/rails webpacker:install:react
Se trata del presentado en [LEARNETTO2020], sólo que traduciendo lo que es posible a español como es estándar en Pasos de Jesús
y empleando class
en lugar de funciones para definir componentes.
Renombre el archivo app/javascript/packs/hello_react.jsx
por app/javascript/packs/hola_react.jsx
y remplace Hello
por Hola
y
name
por nombre
para obtener:
import React from 'react'
import ReactDOM from 'react-dom'
import PropTypes from 'prop-types'
class Hola extends React.Component {
render () {
return <div>Holaa {this.props.nombre}!</div>
}
defaultProps = {
nombre: 'David'
}
}
Hola.propTypes = {
nombre: PropTypes.string
}
export default Hola
document.addEventListener('DOMContentLoaded', () => {
ReactDOM.hydrate(
<Hola nombre="React" />,
document.querySelector('div.caso_ubicacion_tclase'),
)
})
Note que el componente Hola tiene un atributo nombre
(llamado prop
en react).
Cree:
- Un nuevo controlador
app/controllers/holareact_controller.rb
con:
class HolareactController < ApplicationController
def index
render 'index', layout: nil
end
end
- Una nueva vista que cargue el javascript generado a partir de jsx, por ejemplo
app/views/holareact/index.html.erb
con
<%= javascript_pack_tag 'hola_react' %>
- Y finalmente agregue una ruta al nuevo controlador por ejemplo la ruta raíz en
config/routes.rb
root 'holareact#index'
También podrá incluir el <%= javascript_pack_tag 'hola_react' %>
en una vista existente pero puede que tenga que cargarla y recargarla para ver el mensaje insertado al final de la página. Se debe a incompatibilidad entre React y Turbolinks. Por lo mismo una solución es deshabilitar Turbolinks cuando va a cargar la página donde usa React, por ejemplo desde una opción del menú puede hacerlo con:
<%= opcion_menu "Validar casos", sivel2_gen.validarcasos_path,
'data-turbolinks' => false,
desplegable: true %>
o desde un enlace con:
<%= link_to 'Edita', edit_caso_path(caso_id),
data: { turbolinks: false },
:class => 'btn btn-sm' %>
Si desea incluir el componente de react en un elemento de una vista servidor por rails (por ejemplo en un formulario), es más apropiado usar ReactDOM.hydrate
en lugar de ReactDOM.render
(ver [hydrate-2020]), como se presenta en el siguiente ejemplo:
ReactDOM.hydrate(
<Hola nombre="React" />,
document.querySelector('div.caso_ubicacion_tclase'),
)
Para depurar aplicaciones que usen react recomendamos la extensión React Developers Tools disponibles en la tienda de Chrome. Al inspeccionar unas fuentes presentará dos nuevos menús Components
y Profiler
que permiten examinar los componentes presentes en una página y sus props y estado.
react-rails
incluye un ayudador para agregar un componente react desde una vista y propone un directorio para ubicar los componentes: app/javascript/components
.
Después de haber incluido react como se explicó en la sección anterior, incluya la gema react-rails
en su `Gemfile:
gem 'react-rails'
Instale y ejecute un instalador
bundle install
rails generate react:install
Esto agregará el paquete yarn react_ujs
y en su su archivo app/javascript/packs/application.js
agregará las líneas siguientes:
var componentRequireContext = require.context("components", true);
var ReactRailsUJS = require("react_ujs");
ReactRailsUJS.useContext(componentRequireContext);
que indican que la ruta a componentes será components
y que cargan el paquete react_ujs
.
Cómo indica [REACTRAILS2020] puede generar un componente con:
bin/rails g react:component HolaMundo saludo:string
que creará el archivo app/javascript/components/HolaMundo.js
(siempre usa la ruta app/javascript/components/
) con el siguiente contenido:
import React from "react"
import PropTypes from "prop-types"
class HolaMundo extends React.Component {
render () {
return (
<React.Fragment>
Saludo: {this.props.saludo}
</React.Fragment>
);
}
}
HolaMundo.propTypes = {
saludo: PropTypes.string
};
export default HolaMundo
Y que puede incrustarse en vistas usando el ayudador:
<%= react_component('HolaMundo', {saludo: 'Hola desde react-rails'}) %>
teniendo en cuenta la incompatibilidad con Turbolinks y las posibilidades para mitigar el conflicto dadas en la sección anterior.
Un ejemplo basado en [CRUZ2020] de un componente (digamos Tclase
) con dos campos de un formulario cuyo valor se mantiene en el estado del componente, puede definirse en app/javascript/component/Tclase.jsx
:
import React, {useState, Fragment} from 'react'
import ReactDOM from 'react-dom'
class Tclase extends React.Component {
constructor(props) {
super(props);
this.state = {
clase: '',
tclase: ''
}
this.manejaCambio = this.manejaCambio.bind(this);
}
manejaCambio(event) {
var ce = {}
ce[event.target.name] = event.target.value
this.setState(ce)
}
render() {
return (
<Fragment>
<label htmlFor="clase">Centro poblado</label>
<select
className="form-control"
id="clase"
name="clase"
onChange={this.manejaCambio} >
<option>Mosquera</option>
<option>Madrid</option>
<option>Facatativa</option>
</select>
<label htmlFor="tclase">Tipo de centro poblado</label>
<select className="form-control"
id="tclase"
name="tclase"
onChange={this.manejaCambio} >
<option>Cabecera Municipal</option>
<option>Centro poblado</option>
</select>
<p>{JSON.stringify(this.state)}</p>
</Fragment>
)
}
}
export default Tclase
Note que:
- Como se explica en [REACTESTADO-2020] el estado se mantiene en
this.state
, y para que la funciónmanejaCambio
tenga acceso se requiere en la constructora la asignación:
this.manejaCambio = this.manejaCambio.bind(this);
- El estado se actualiza mediante la función
setState
.
Y en el formulario donde se va a usar se agrega:
<%= react_component('Tclase') %>
- [LEARNETTO2020] https://learnetto.com/blog/react-rails
- [hydrate2020] https://reactjs.org/docs/react-dom.html#hydrate
- [REACTRAILS2020] https://github.com/reactjs/react-rails/blob/master/README.md
- [REACTESTADO2020] https://reactjs.org/docs/state-and-lifecycle.html
- [CRUZ2020] Ejemplo de componente funcional que mantiene estado. https://github.com/pasosdeJesus/sivel2_gen/commit/c17822c3b0f79c52b391f6098e6487a6f26c581c
Desarrollado por Pasos de Jesús. Dominio público de acuerdo a legislación colombiana. Agradecemos financiación para personalizaciones de dominio público a diversas organizaciones, ver https://github.com/pasosdeJesus/sivel2/blob/master/CREDITOS.md
- Validación de etiquetas de Colombia y sus departamentos entre OSM de Sep.2022 y DIVIPOLA 2022
- Actualización a DIVIPOLA 2022-07 y Resumen ejecutivo de la actualización a DIVIPOLA 2022-07
- Actualización a DIVIPOLA 2021 y Resumen ejecutivo de la actualización a DIVIPOLA 2021
- Actualización a Rails 7
- Actualización a DIVIPOLA 2020 y Resumen ejecutivo de la actualización a DIVIPOLA 2020
- Extensiones para Chomium útiles para desarrollo
- Actualización de sip 2.0b11 a 2.0b12
- Actualización de sip 2.0b10 a 2.0b11
- Actualización de Rails 6.0 a Rails 6.1
- Resumen ejecutivo de la actualización a DIVIPOLA 2019
- Actualización a DIVIPOLA 2019
- Actualización-de-sip-2.0b6-a-sip-2.0b7
- Pasando de sprockets a webpacker con Rails 6
- Actualización a Rails 6 en 6 pasos
- Actualización a DIVIPOLA 2018
- Actualización de Rails 5.1 a Rails 5.2
- Actualizando a Rails 5
- Actualización a PostgreSQL posterior a 10.2