Skip to content
Conversor de medidas en ReactJS
JavaScript HTML CSS
Branch: master
Clone or download
Fetching latest commit…
Cannot retrieve the latest commit at this time.
Permalink
Type Name Latest commit message Commit time
Failed to load latest commit information.
.vscode
images
public
src
video
.gitignore
.travis.yml
README.md
package-lock.json
package.json

README.md

Conversor ReactJS

video

Este proyecto fue generado con el script Create React App.

Arquitectura general

image

El dominio es un objeto que recibe un número que representa las millas y devuelve su valor convertido a kilómetros. No tiene variables de instancia. Se puede ver en el archivo conversor.js del directorio src:

export default class Conversor {
    convertir(millas) {
        return millas * 1.60934
    }
}

La vista tiene

  • como estado una sola clave: "kilometros" que apunta al valor convertido.
  • un input type text cuyo evento onChange dispara la conversión
  • al convertir se actualiza el state del componente generando un nuevo conversor y llamando al convertir. El valor resultante va a parar a la única variable kilometros.

Esto puede verse en el archivo App.js del directorio src:

class App extends Component {
  constructor() {
    super()
    this.state = { kilometros: "<Ingrese millas>" }
    this.convertir = this.convertir.bind(this)
  }
  
  convertir(event) {
    this.setState({
      kilometros: new Conversor().convertir(event.target.value)
    })
  }

  render() {
    return (
      <div className="App">
        <div className="App-header">
          <img src={logo} className="App-logo" alt="logo" />
          <h1>Conversor <small>React JS</small></h1>
        </div>
        <p>Ingrese millas:</p>
        <input type="text" name="millas" id="millas" onChange={this.convertir} />
        <p>Ingrese kilómetros:</p>
        <p id="kms">{this.state.kilometros.toLocaleString('es')}</p>
      </div>
    );
  }
}

Entendiendo el binding de eventos

En este articulo se explica que cuando definimos una función en Javascript, la variable this se refiere al contexto de ejecución de dicha función:

// esto se puede ejecutar en cualquier browser
let frog = {
  RUN_SOUND: "POP!!",
  run: function() { 
    console.log('this es ', this)
    return this.RUN_SOUND
  }
}

Si frog es un objeto, y vemos run() como un método de dicho objeto, lo natural es que pensemos en enviar el mensaje de la siguiente manera:

> frog.run() 
this es  {RUN_SOUND: "POP!!", run: ƒ}
"POP!!"

Pero ECMAScript es también un lenguaje funcional, entonces puedo definir una variable y construir una función a partir del método definido en frog:

> const f = frog.run

Ojo que al no pasarle paréntesis, no estamos invocando a la función, sino referenciando con la variable f a la función frog.run, que no recibe parámetros y devuelve un string.

Cuando invocamos a f, nuestra sorpresa:

> f()
this es  Window {postMessage: ƒ, blur: ƒ, focus: ƒ, close: ƒ, frames: Window, …}
undefined

La variable this no está ligada a frog, sino a window (nuestro browser). Al extraer f como variable separada del objeto frog, perdimos el contexto de ejecución de this. Para poder recuperarlo, necesitamos la función bind:

> const fParaFrog = f.bind(frog)
> fParaFrog()
this es  {RUN_SOUND: "POP!!", run: ƒ}
"POP!!"
// o bien...
> f.bind(frog)() // ...que produce el mismo resultado

Por ese motivo, queremos que al invocar a convertir las millas en kilómetros, this referencie a nuestro componente React y no a window. Entonces aplicamos el bind en el constructor:

class App extends Component {
  constructor() {
    ...
    this.convertir = this.convertir.bind(this)
  }

Por qué lo hacemos? Porque en la función render asociamos el evento onChange a la referencia convertir de nuestra App, que de otra forma sería una función sin contexto asociado:

        <input type="text" name="millas" id="millas" onChange={this.convertir} />

Otros artículos que recomendamos leer:

Ciclo de vida

image

Testing

Para testear el componente probamos

  • que la aplicación levanta correctamente
  • que inicialmente el valor en kilómetros dice "<Ingrese millas>"
  • que al escribir el valor "10" en millas eso convierte a "16.093"

Dado que estaremos usando los mocks de Enzyme, no se convierte el punto decimal a coma.

Vemos los tests en el archivo App.test.js del directorio src:

it('App levanta', () => {
  shallow(<App />)
})
it('convertir 10 millas a kilómetros', () => {
  const wrapper = shallow(<App/>)
  const kms = wrapper.find('#kms')
  expect(kms.text()).toBe("<Ingrese millas>")
})
it('convertir 10 millas a kilómetros', () => {
  const wrapper = shallow(<App/>)
  const millas = wrapper.find('#millas')
  millas.simulate('change', { 'target': { value: '10'}})
  const kms = wrapper.find('#kms')
  expect(kms.text()).toBe("16.093")
})
You can’t perform that action at this time.