Comment puis-je demander à React de restituer la vue lorsque la fenêtre du navigateur est redimensionnée?
Contexte
J'ai des blocs que je souhaite mettre en page individuellement sur la page, mais je veux également qu'ils soient mis à jour lorsque la fenêtre du navigateur change. Le résultat final sera quelque chose comme la mise en page Pinterest de Ben Holland , mais écrit en utilisant React et pas seulement jQuery. Je suis encore loin.
Code
Voici mon application:
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')
)
Ensuite, j'ai le Block
composant (équivalent à un Pin
dans l'exemple Pinterest ci-dessus):
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>
);
}
});
et la liste / collection 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>
);
}
});
Question
Dois-je ajouter un redimensionnement de la fenêtre de jQuery? Si oui, où?
$( window ).resize(function() {
// re-render the component
});
Existe-t-il une façon plus «réactive» de procéder?
la source
this.updateDimensions
passé àaddEventListener
est juste une référence de fonction nue qui n'aura aucune valeurthis
lors de son appel. Faut-il ajouter une fonction anonyme ou un appel .bind ()this
, ou ai-je mal compris?this
pour toutes les méthodes définies directement sur le composant.innerHeight
et àinnerWidth
partir dewindow
. Et vous pouvez ignorercomponentWillMount
si vous utilisezgetInitialState
pour définirheight
etwidth
.::
syntaxe de liaison soit sortie pour l'instant sitepoint.com/bind-javascripts-this-keyword-react "l'opérateur de liaison (: :) ne fera pas partie d'ES7, car l'ensemble des fonctionnalités ES7 a été gelé en février , l'opérateur de liaison est une proposition pour ES8 "@SophieAlpert a raison, +1, je veux juste fournir une version modifiée de sa solution, sans jQuery , basée sur cette réponse .
la source
Une solution très simple:
la source
componentWillUnmount()
!forceUpdate
application est conditionnelleC'est un exemple simple et court d'utilisation d'es6 sans jQuery.
crochets
la source
::
opérateur de liaison renvoie une nouvelle valeur chaque fois qu'elle est appliquée. Ainsi, votre écouteur d'événements ne sera pas réellement enregistré, car vousremoveEventListener
finirez par transmettre une fonction différente de celle à laquelle il a été transmis à l'origineaddEventListener
.À partir de React 16.8, vous pouvez utiliser des crochets !
la source
Edit 2018 : maintenant React a un support de première classe pour le contexte
Je vais essayer de donner une réponse générique, qui cible ce problème spécifique mais aussi un problème plus général.
Si vous ne vous souciez pas des bibliothèques d' effets secondaires, vous pouvez simplement utiliser quelque chose comme Packery
Si vous utilisez Flux, vous pouvez créer un magasin contenant les propriétés de la fenêtre afin de conserver une fonction de rendu pure sans avoir à interroger l'objet fenêtre à chaque fois.
Dans d'autres cas, lorsque vous souhaitez créer un site Web réactif mais que vous préférez les styles en ligne React aux requêtes multimédias ou que le comportement HTML / JS change en fonction de la largeur de la fenêtre, continuez à lire:
Qu'est-ce que le contexte React et pourquoi j'en parle
Le contexte React n'est pas dans l'API publique et permet de transmettre des propriétés à toute une hiérarchie de composants.
Le contexte React est particulièrement utile pour transmettre à l'ensemble de votre application des choses qui ne changent jamais (il est utilisé par de nombreux frameworks Flux via un mixin). Vous pouvez l'utiliser pour stocker des invariants commerciaux d'application (comme l'ID utilisateur connecté, afin qu'il soit disponible partout).
Mais il peut également être utilisé pour stocker des choses qui peuvent changer. Le problème est que lorsque le contexte change, tous les composants qui l'utilisent doivent être restitués et ce n'est pas facile à faire, la meilleure solution est souvent de démonter / remonter l'application entière avec le nouveau contexte. N'oubliez pas que forceUpdate n'est pas récursif .
Donc, comme vous le comprenez, le contexte est pratique, mais il y a un impact sur les performances lorsqu'il change, il ne devrait donc pas changer trop souvent.
Que mettre en contexte
Voici des choses qui ne changent pas souvent:
La langue actuelle de l'utilisateur :
Il ne change pas très souvent, et quand il le fait, comme toute l'application est traduite, nous devons tout restituer: une très belle utilisation du changement de langage à chaud
Les propriétés de la fenêtre
La largeur et la hauteur ne changent pas souvent, mais lorsque nous le faisons, notre disposition et notre comportement peuvent devoir s'adapter. Pour la mise en page, il est parfois facile de personnaliser avec les médias CSS, mais parfois ce n'est pas le cas et nécessite une structure HTML différente. Pour le comportement, vous devez gérer cela avec Javascript.
Vous ne voulez pas tout restituer à chaque événement de redimensionnement, vous devez donc annuler les événements de redimensionnement.
Ce que je comprends de votre problème, c'est que vous voulez savoir combien d'éléments afficher en fonction de la largeur de l'écran. Vous devez donc d'abord définir des points d'arrêt réactifs et énumérer le nombre de types de disposition différents que vous pouvez avoir.
Par exemple:
Lors des événements de redimensionnement (anti-rebond), vous pouvez facilement obtenir le type de mise en page actuel en interrogeant l'objet fenêtre.
Ensuite, vous pouvez comparer le type de mise en page avec l'ancien type de mise en page, et s'il a changé, restituez l'application avec un nouveau contexte: cela permet d'éviter de restituer l'application du tout lorsque l'utilisateur a déclenché des événements de redimensionnement mais en fait le le type de mise en page n'a pas changé, vous ne devez donc effectuer un nouveau rendu qu'en cas de besoin.
Une fois que vous avez cela, vous pouvez simplement utiliser le type de mise en page à l'intérieur de votre application (accessible via le contexte) afin de pouvoir personnaliser le HTML, le comportement, les classes CSS ... Vous connaissez votre type de mise en page dans la fonction de rendu React, cela signifie donc que vous peut écrire en toute sécurité des sites Web réactifs en utilisant des styles en ligne, et n'a pas besoin du tout de mediaqueries.
Si vous utilisez Flux, vous pouvez utiliser un magasin au lieu du contexte React, mais si votre application a beaucoup de composants réactifs, il est peut-être plus simple d'utiliser le contexte?
la source
J'utilise la solution de @senornestor, mais pour être tout à fait correct, vous devez également supprimer l'écouteur d'événements:
Sinon, vous obtiendrez l'avertissement:
la source
Je sauterais toutes les réponses ci-dessus et commencerais à utiliser le
react-dimensions
composant d'ordre supérieur.https://github.com/digidem/react-dimensions
Ajoutez simplement un simple
import
et un appel de fonction, et vous pouvez accéder àthis.props.containerWidth
etthis.props.containerHeight
dans votre composant.la source
react-dimensions
fonctionne même pour les dimensions modifiées par programme (par exemple, la taille d'un div a changé, ce qui affecte la taille de votre conteneur, vous devez donc mettre à jour votre taille). La réponse de Ben Alpert n'aide que les événements de redimensionnement de la fenêtre du navigateur. Voir ici: github.com/digidem/react-dimensions/issues/4react-dimensions
gère les changements de taille de la fenêtre, les changements de disposition de la boîte flexible et les changements dus au redimensionnement JavaScript. Je pense que cela le couvre. Avez-vous un exemple qu'il ne gère pas correctement?window.innerWidth
,window.innerHeight
.react-dimensions
résout la partie la plus importante du problème et déclenche également votre code de mise en page lorsque la fenêtre est redimensionnée (ainsi que lorsque la taille du conteneur change).Ce code utilise la nouvelle API de contexte React :
Ensuite, vous pouvez l'utiliser où vous le souhaitez dans votre code comme ceci:
la source
Vous n'avez pas nécessairement besoin de forcer un nouveau rendu.
Cela pourrait ne pas aider OP, mais dans mon cas, je n'avais besoin que de mettre à jour les attributs
width
etheight
sur ma toile (ce que vous ne pouvez pas faire avec CSS).Cela ressemble à ceci:
la source
Je ne sais pas si c'est la meilleure approche, mais ce qui a fonctionné pour moi a d'abord été de créer un magasin, je l'ai appelé WindowStore:
Ensuite, j'ai utilisé ce magasin dans mes composants, un peu comme ceci:
Pour info, ces fichiers ont été partiellement rognés.
la source
onresize
pourrait envoyer unWindowResizedAction
.Je sais que cela a été répondu, mais je pensais juste partager ma solution car la meilleure réponse, bien que géniale, peut maintenant être un peu dépassée.
La seule différence est que je fais rebondir (uniquement toutes les 200 ms) les updateWindowDimensions sur l'événement resize pour augmenter un peu les performances, MAIS je ne les rebondis pas quand il est appelé sur ComponentDidMount.
Je trouvais que le rebounce le rendait assez lent à monter parfois si vous avez une situation où il monte souvent.
Juste une optimisation mineure mais j'espère que cela aide quelqu'un!
la source
initUpdateWindowDimensions
méthode?Juste pour améliorer la solution de @ senornestor à utiliser
forceUpdate
et la solution de @ gkri pour supprimer l'resize
écouteur d'événements lors du démontage du composant:bind(this)
dans le constructeurUne autre méthode consiste à utiliser simplement un état "factice" au lieu de
forceUpdate
:la source
Il suffit de définir la fonction d'événement de redimensionnement.
Mettez ensuite à jour la taille du rendu (canevas), attribuez un nouveau format d'image à la caméra.
Le démontage et le rappel est une solution folle à mon avis ....
ci-dessous est le support si nécessaire.
la source
Je voulais partager cette chose assez cool que je viens de trouver en utilisant
window.matchMedia
.matches
renvoie true ou false si la fenêtre est supérieure ou inférieure à la valeur de largeur maximale spécifiée, cela signifie qu'il n'est pas nécessaire de limiter l'écouteur, car matchMedia ne se déclenche qu'une seule fois lorsque le booléen change.Mon code peut facilement être ajusté pour inclure
useState
pour enregistrer les retours booléens matchMedia, et l'utiliser pour rendre conditionnellement un composant, déclencher une action, etc.la source
J'ai dû le lier à «this» dans le constructeur pour le faire fonctionner avec la syntaxe de classe
la source
Merci à tous pour les réponses. Voici mon React + Recompose . Il s'agit d'une fonction d'ordre élevé qui inclut les propriétés
windowHeight
etwindowWidth
du composant.la source
https://github.com/renatorib/react-sizes est un HOC pour ce faire tout en conservant de bonnes performances.
la source
Pour cette raison, il vaut mieux utiliser ces données à partir de données de fichiers CSS ou JSON, puis avec ces données, définir un nouvel état avec this.state ({width: "some value", height: "some value"}); ou écrire du code qui utilise des données d'écran de largeur dans le travail autonome si vous souhaitez afficher des images réactives
la source