¿Cómo puedo hacer que React vuelva a representar la vista cuando se cambia el tamaño de la ventana del navegador?
Antecedentes
Tengo algunos bloques que quiero diseñar individualmente en la página, sin embargo, también quiero que se actualicen cuando cambie la ventana del navegador. El resultado final será algo así como el diseño de Pinterest de Ben Holland , pero escrito usando React no solo jQuery. Todavía estoy muy lejos.
Código
Aquí está mi aplicación:
var MyApp = React.createClass({
//does the http get from the server
loadBlocksFromServer: function() {
$.ajax({
url: this.props.url,
dataType: 'json',
mimeType: 'textPlain',
success: function(data) {
this.setState({data: data.events});
}.bind(this)
});
},
getInitialState: function() {
return {data: []};
},
componentWillMount: function() {
this.loadBlocksFromServer();
},
render: function() {
return (
<div>
<Blocks data={this.state.data}/>
</div>
);
}
});
React.renderComponent(
<MyApp url="url_here"/>,
document.getElementById('view')
)
Luego tengo el Block
componente (equivalente a a Pin
en el ejemplo de Pinterest anterior):
var Block = React.createClass({
render: function() {
return (
<div class="dp-block" style={{left: this.props.top, top: this.props.left}}>
<h2>{this.props.title}</h2>
<p>{this.props.children}</p>
</div>
);
}
});
y la lista / colección de Blocks
:
var Blocks = React.createClass({
render: function() {
//I've temporarily got code that assigns a random position
//See inside the function below...
var blockNodes = this.props.data.map(function (block) {
//temporary random position
var topOffset = Math.random() * $(window).width() + 'px';
var leftOffset = Math.random() * $(window).height() + 'px';
return <Block order={block.id} title={block.summary} left={leftOffset} top={topOffset}>{block.description}</Block>;
});
return (
<div>{blockNodes}</div>
);
}
});
Pregunta
¿Debo agregar el cambio de tamaño de la ventana de jQuery? ¿Si es así, donde?
$( window ).resize(function() {
// re-render the component
});
¿Hay una manera más "Reaccionar" de hacer esto?
fuente
this.updateDimensions
pasado aaddEventListener
es solo una referencia de función desnuda que no tendrá valor parathis
cuando se llama. ¿Debería usarse una función anónima, o una llamada .bind () para agregarthis
, o he entendido mal?this
para cualquier método definido directamente en el componente.innerHeight
yinnerWidth
fromwindow
. Y puede omitircomponentWillMount
si usagetInitialState
para configurarheight
ywidth
.::
sintaxis de BIND es por ahora sitepoint.com/bind-javascripts-this-keyword-react "el operador bind (: :) no va a ser parte de ES7, ES7 como el conjunto de características se congeló en febrero , el operador de enlace es una propuesta para ES8 "@SophieAlpert tiene razón, +1, solo quiero proporcionar una versión modificada de su solución, sin jQuery , basada en esta respuesta .
fuente
Una solución muy simple:
fuente
componentWillUnmount()
!forceUpdate
se aplica condicionalmenteEs un ejemplo simple y breve del uso de es6 sin jQuery.
manos
fuente
::
operador de enlace devuelve un nuevo valor cada vez que se aplica. Por lo tanto, su escucha de eventos en realidad no quedará sin registrar, ya queremoveEventListener
termina pasando una función diferente a la que se le pasó originalmenteaddEventListener
.¡A partir de React 16.8 puedes usar Hooks !
fuente
Edit 2018 : ahora React tiene soporte de primera clase para el contexto
Trataré de dar una respuesta genérica, que aborde este problema específico pero también un problema más general.
Si no le importan las bibliotecas de efectos secundarios, simplemente puede usar algo como Packery
Si usa Flux, podría crear una tienda que contenga las propiedades de la ventana para mantener una función de renderización pura sin tener que consultar el objeto de la ventana cada vez.
En otros casos en los que desea crear un sitio web receptivo pero prefiere Reaccionar estilos en línea a consultas de medios, o desea que el comportamiento de HTML / JS cambie de acuerdo con el ancho de la ventana, siga leyendo:
¿Qué es el contexto React y por qué hablo?
El contexto de reacción no está en la API pública y permite pasar propiedades a toda una jerarquía de componentes.
El contexto de reacción es particularmente útil para pasar a toda su aplicación cosas que nunca cambian (es utilizado por muchos frameworks Flux a través de un mixin). Puede usarlo para almacenar invariantes comerciales de aplicaciones (como el ID de usuario conectado, para que esté disponible en todas partes).
Pero también se puede usar para almacenar cosas que pueden cambiar. El problema es que cuando el contexto cambia, todos los componentes que lo usan deben volverse a renderizar y no es fácil hacerlo, la mejor solución a menudo es desmontar / volver a montar toda la aplicación con el nuevo contexto. Recuerde forceUpdate no es recursivo .
Entonces, como comprende, el contexto es práctico, pero hay un impacto en el rendimiento cuando cambia, por lo que no debería cambiar con demasiada frecuencia.
Qué poner en contexto
Aquí hay cosas que no cambian a menudo:
El idioma del usuario actual :
No cambia muy a menudo, y cuando lo hace, a medida que se traduce toda la aplicación, tenemos que volver a renderizar todo: un caso muy útil de cambio de idioma.
Las propiedades de la ventana
El ancho y la altura no cambian con frecuencia, pero cuando lo hacemos, nuestro diseño y comportamiento pueden tener que adaptarse. Para el diseño, a veces es fácil de personalizar con CSS mediaqueries, pero a veces no lo es y requiere una estructura HTML diferente. Para el comportamiento tienes que manejar esto con Javascript.
No desea volver a renderizar todo en cada evento de cambio de tamaño, por lo que debe eliminar los eventos de cambio de tamaño.
Lo que entiendo de su problema es que desea saber cuántos elementos mostrar de acuerdo con el ancho de la pantalla. Por lo tanto, primero debe definir puntos de interrupción receptivos y enumerar el número de diferentes tipos de diseño que puede tener.
Por ejemplo:
En eventos de cambio de tamaño (sin rebote), puede obtener fácilmente el tipo de diseño actual consultando el objeto de la ventana.
Luego puede comparar el tipo de diseño con el tipo de diseño anterior, y si ha cambiado, vuelva a renderizar la aplicación con un nuevo contexto: esto permite evitar volver a renderizar la aplicación cuando el usuario ha activado eventos de cambio de tamaño, pero en realidad el el tipo de diseño no ha cambiado, por lo que solo se vuelve a generar cuando es necesario.
Una vez que tenga eso, simplemente puede usar el tipo de diseño dentro de su aplicación (accesible a través del contexto) para que pueda personalizar el HTML, el comportamiento, las clases de CSS ... Conozca su tipo de diseño dentro de la función React render, por lo que esto significa que puede escribir sitios web receptivos de forma segura mediante el uso de estilos en línea, y no necesita consultas multimedia en absoluto.
Si usa Flux, puede usar una tienda en lugar de React context, pero si su aplicación tiene muchos componentes receptivos, ¿tal vez sea más simple usar context?
fuente
Uso la solución de @senornestor, pero para ser completamente correcto, también debes eliminar el detector de eventos:
De lo contrario, recibirá la advertencia:
fuente
Me saltaría todas las respuestas anteriores y comenzaría a usar el
react-dimensions
Componente de orden superior.https://github.com/digidem/react-dimensions
Simplemente agregue una
import
llamada simple y una función, y puede accederthis.props.containerWidth
ythis.props.containerHeight
en su componente.fuente
react-dimensions
incluso funciona para dimensiones cambiadas programáticamente (por ejemplo, el tamaño de un div cambiado, que afecta el tamaño de su contenedor, por lo que debe actualizar su tamaño). La respuesta de Ben Alpert solo ayuda en los eventos de cambio de tamaño de la ventana del navegador. Ver aquí: github.com/digidem/react-dimensions/issues/4react-dimensions
maneja cambios en el tamaño de la ventana, cambios en el diseño de flexbox y cambios debido al cambio de tamaño de JavaScript. Creo que eso lo cubre. ¿Tienes un ejemplo de que no se maneja correctamente?window.innerWidth
,window.innerHeight
.react-dimensions
resuelve la parte más importante del problema y también activa su código de diseño cuando se cambia el tamaño de la ventana (así como cuando cambia el tamaño del contenedor).Este código está utilizando la nueva API de contexto React :
Luego puede usarlo donde quiera en su código de esta manera:
fuente
No necesariamente necesita forzar una nueva representación.
Puede que esto no ayude a OP, pero en mi caso solo necesitaba actualizar los atributos
width
yheight
en mi lienzo (que no puede hacer con CSS).Se parece a esto:
fuente
No estoy seguro si este es el mejor enfoque, pero lo que funcionó para mí fue crear primero una Tienda, la llamé WindowStore:
Luego usé esa tienda en mis componentes, algo así:
Para su información, estos archivos se recortaron parcialmente.
fuente
onresize
podría enviar aWindowResizedAction
.Sé que esto ha sido respondido, pero pensé que compartiría mi solución como la respuesta principal, aunque excelente, ahora puede estar un poco desactualizado.
La única diferencia realmente es que estoy eliminando (solo ejecutando cada 200 ms) el updateWindowDimensions en el evento de cambio de tamaño para aumentar un poco el rendimiento, PERO no lo elimino cuando se llama en ComponentDidMount.
Descubrí que el rebote hace que sea bastante lento montarlo a veces si tienes una situación en la que se está montando a menudo.
¡Solo una pequeña optimización, pero espero que ayude a alguien!
fuente
initUpdateWindowDimensions
método?Solo para mejorar la solución de @ senornestor para usar
forceUpdate
y la solución de @ gkri para eliminar elresize
detector de eventos en el desmontaje del componente:bind(this)
en el constructorOtro método es usar un estado "ficticio" en lugar de
forceUpdate
:fuente
Solo es necesario definir la función de cambio de tamaño del evento.
Luego actualice el tamaño de los renderizadores (lienzo), asigne una nueva relación de aspecto para la cámara.
Desmontar y enrutar es una solución loca en mi opinión ...
a continuación se muestra el montaje si es necesario.
fuente
Quería compartir esta cosa genial que encontré usando
window.matchMedia
.matches
devolverá verdadero o falso si la ventana es más alta o más baja que el valor de ancho máximo especificado, esto significa que no hay necesidad de estrangular al oyente, ya que matchMedia solo se dispara una vez cuando cambia el valor booleano.Mi código se puede ajustar fácilmente para incluir
useState
para guardar los retornos booleanos de matchMedia y usarlo para representar condicionalmente un componente, acción de disparo, etc.fuente
Tuve que vincularlo a 'this' en el constructor para que funcione con la sintaxis de Class
fuente
Gracias a todos por las respuestas. Aquí está mi React + Recompose . Es una función de orden superior que incluye el
windowHeight
ywindowWidth
propiedades al componente.fuente
https://github.com/renatorib/react-sizes es un HOC para hacer esto mientras se mantiene un buen rendimiento.
fuente
Por esta razón, es mejor si usa estos datos de archivos CSS o JSON, y luego con estos datos estableciendo un nuevo estado con this.state ({ancho: "algún valor", altura: "algún valor"}); o escribir código que use datos de datos de pantalla de ancho en trabajo propio si desea mostrar imágenes receptivas
fuente