Cuando tocó hace un escáner de código QR con React js. Pensé que sería mucho mas fácil ya que en teoría solo era instalar alguna librería via NPM o algo similar. Pero me encontré con algunos problemas.
Empecemos que en existen dos librerías para escanear código QR para React, estos son: React-QR-React y React-QR-Scanner. Ambas tienen un problema en común, y es que no funcionan correctamente tanto en Chrome y funciona a medias en Safari ambos en iPhone.

Instalación de librerías para leer código QR con React
Ambos tienen similitudes pero al final vamos solo a utilizar ambos. Para ello los instalamos ambos y ustedes deciden cual de los dos les funciona mejor a ustedes.
- Instalando React QR react
npm install --save react-qr-reader
- Instalando React QR Scanner
npm install --save react-qr-scanner
Ejemplo de uso
Ambos tienen casi las mismas etiquetas pues Reac-Qr-Scanner esta basado en Reac-Qr-Reader. Solo que el primero tiene actualizaciones mas recientes y es posible que en un futuro arreglen pronto problemas que tengan.
Este código funciona en ambos casos:
import React, { Component } from 'react'
import QrReader from 'react-qr-reader'
// import QrReader from 'react-qr-scanner'
class Test extends Component {
state = {
result: ''
}
handleScan(data){
this.setState({
result: data,
})
}
handleError(err){
console.error(err)
}
render(){
const previewStyle = {
height: 240,
width: 320,
}
return(
<div>
<QrReader
delay={this.state.delay}
style={previewStyle}
onError={this.handleError}
onScan={this.handleScan}
/>
<p>{this.state.result}</p>
</div>
)
}
}
Ambos funcionan en Desktop y en cualquier navegador. Pero una vez probándolo en móvil específicamente en iPhone. Habrán problemas…
- En chrome no nos pedirá permiso para el uso de cámara. Por ende no podemos escanear nada
- En Safari la camara funcionará, pero solo la cámara frontal. Casi imposible escanear algo.
Tendremos que añadir un poco de código para que mas o menos funcione y tengamos algo decente que mostrar.
Cambiar de cámara en Safari / iOs
Según la documentación tenemos la opción de facingMode. Pero necesitamos agregar un botón tener ambas opciones, por lo que necesitaremos un nuevo state, un método para escuchar que sucede y donde colocar el nuevo state
En el state:
facingMode : user
Agregamos un nuevo método para cambiar de camara en caso de ser posible y necesario.
choiceButton= () =>{
if(this.state.facingMode === "environment"){
this.setState({
facingMode: "user"
})
} else {
this.setState({
facingMode: "environment"
})
}
}
Lo agregamos a la etiqueta de <QrReader />
facingMode = {this.state.facingMode}
Esto funciona perfectamente, en teoría funciona correctamente. Pero necesitamos un boton que nos permita cambiar de camara si el caso amerita.
<input type="button" value="Cambiar de cámara" onClick={this.choiceButton} />
Nota: Aclarar que el facingMode funciona mejor con React-Qr-Reader
Agregar adjuntar código QR para Chrome
En ambas librerías su documentación aseguran que colocando el legacyMode funcionara en Chrome, pero al hacerlo nos da un error al activar la cámara y dejan de funcionar. Pero igual necesitamos una solución, aunque en este caso es una opción para los usuarios que accedan a nuestra app desde Chrome / iOs.
Para ello vamos hacer lo siguiente:
Agregamos un nuevo state:
legacyMode: false,
Dentro de la etiqueta < QrReader /> agregamos lo siguiente.
legacyMode = {this.state.legacyMode}
ref = "qrReader"
Modificamos handleError(err) que antes solo mostraba el error por consola. Agregamos los siguiente:
handleScan(err){
this.setState(
{legacyMode: true}
)
}
Ahora, si por algún motivo no podemos acceder a la cámara del usuario activamos el legacyMode y podemos llamar un botón que acceda a la galería. Ahora solo tenemos que llamar dicho boton.
{this.state.legacyMode ? (<input type="button" value="Adjuntar QR" onClick={() =>this.openImageDialog()} />: ('')}
Agregamos el metodo openImageDialog que declaramos con el onClick dentro del input
openImageDialog() { this.ref.qrReader1.openImageDialog() }
Si bien no arreglamos los problemas de acceso de cámara de estas librerías para escanear código QR con React js. Pero al menos le damos una solución viable, hasta que los que mantienen este código puedan arreglar dichos bugs y nos eviten tanto dolor de cabeza.
Código finalizado
import React, { Component } from 'react'
import QrReader from 'react-qr-reader'
// import QrReader from 'react-qr-scanner'
class Test extends Component {
state = {
result: '',
facingMode : user,
legacyMode: false,
}
handleScan(data){
this.setState({
result: data,
})
}
handleError(err){
this.setState(
{legacyMode: true}
)
}
choiceButton= () =>{
if(this.state.facingMode === "environment"){
this.setState({
facingMode: "user"
})
} else {
this.setState({
facingMode: "environment"
})
}
}
openImageDialog() { this.ref.qrReader1.openImageDialog() }
render(){
const previewStyle = {
height: 240,
width: 320,
}
return(
<div>
<QrReader
delay={this.state.delay}
style={previewStyle}
onError={this.handleError}
onScan={this.handleScan}
/>
<input type="button" value="Cambiar de cámara" onClick={this.choiceButton} />
{this.state.legacyMode ? (<input type="button" value="Adjuntar QR" onClick={()
=>this.openImageDialog()} />: ('')}
<p>{this.state.result}</p>
</div>
)
}
}