Effectuer des anti-rebond dans React.js
Comment procédez-vous pour anti-rebond dans React.js?
Je veux antirebond de la handleOnChange.
J'ai essayé avec debounce(this.handleOnChange, 200)
mais ça ne fonctionne pas.
function debounce(fn, delay) {
var timer = null;
return function() {
var context = this,
args = arguments;
clearTimeout(timer);
timer = setTimeout(function() {
fn.apply(context, args);
}, delay);
};
}
var SearchBox = React.createClass({
render: function() {
return <input type="search" name="p" onChange={this.handleOnChange} />;
},
handleOnChange: function(event) {
//make ajax call
}
});
- J'ai rencontré le même problème avec vous, superbe réponses ci-dessous!mais je pense que vous avez utilisé de mauvaise façon de
debounce
. ici, quandonChange={debounce(this.handleOnChange, 200)}/>
, il appelleradebounce function
à chaque fois. mais ,en fait, nous avons besoin d'invoquer la fonction de ce antirebond fonction renvoyée.
Vous devez vous connecter pour publier un commentaire.
2019: essayez de crochets + promesse anti-rebond
C'est la plus à jour la version de comment je pourrais résoudre ce problème. Je voudrais utiliser:
C'est une première câblage, mais de la rédaction primitive des blocs sur votre propre, et vous pouvez faire votre propre crochet de sorte que vous ne devez faire qu'une seule fois.
Et ensuite vous pouvez utiliser votre crochet:
Vous trouverez cet exemple exécute ici et vous devriez lire réagir-async-crochet documentation pour plus de détails.
2018: essayez promesse anti-rebond
On a souvent envie de antirebond des appels API pour éviter d'inonder le backend inutile demandes.
En 2018, en travaillant avec des rappels (Lodash/Trait) se sent mal et sujettes à l'erreur pour moi. Il est facile de rencontrer des standard et des problèmes de concurrence, en raison des appels de l'API de résoudre dans un ordre arbitraire.
J'ai créé une petite bibliothèque avec de Réagir à l'esprit pour résoudre vos douleurs: génial d'anti-rebond-la promesse.
Cela ne devrait pas être plus compliqué que cela:
Le sans rebond fonction garantit que:
this.setState({ result });
va se passer par appel d'APIPar la suite, vous pouvez ajouter une autre astuce si votre composant démonte:
Noter que Observables (RxJS) peut également être un grand ajustement pour l'anti-rebond des entrées, mais il est plus puissant que l'abstraction qui peut être plus difficile à apprendre/utiliser correctement.
< 2017: voulez toujours utiliser de rappel anti-rebond?
L'important est ici pour créer un unique sans rebond (ou limitée) de la fonction par l'instance du composant. Vous ne voulez pas de recréer l'anti-rebond (ou papillon) de la fonction à chaque fois, et vous ne voulez pas plusieurs instances partagent les mêmes sans rebond de la fonction.
Je ne suis pas la définition d'une fonction anti-rebond dans cette réponse, car il n'est pas vraiment pertinent, mais cela fonctionne parfaitement bien avec
_.debounce
de soulignement ou lodash, ainsi que toute fournies par l'utilisateur fonction anti-rebond.BONNE IDÉE:
Parce que sans rebond fonctions sont dynamiques, nous devons créer un sans rebond de la fonction par l'instance du composant.
ES6 (propriété de la classe): recommandé
ES6 (le constructeur de la classe)
ES5
Voir JsFiddle: 3 instances de production de 1 entrée de journal par exemple (cela fait 3 dans le monde).
PAS une bonne idée:
Ça ne marchera pas, parce que pendant la classe description de la création d'objet,
this
n'est pas l'objet lui-même créé.this.method
ne renvoie pas à quoi vous attendre parce que lethis
contexte n'est pas l'objet lui-même (qui en réalité n'existe pas vraiment encore BTW que c'est juste d'être créé).PAS une bonne idée:
Cette fois, vous êtes effectivement la création d'un sans rebond fonction qui appelle votre
this.method
. Le problème, c'est que vous êtes le recréer à chaquedebouncedMethod
appel, de sorte que le nouvellement créé fonction anti-rebond ne sait rien sur l'ancien appels! Vous devez réutiliser le même sans rebond fonction au cours du temps ou de l'anti-rebond ne se fera pas.PAS une bonne idée:
C'est un peu difficile ici.
Tous les montées des instances de la classe partagent la même sans rebond de la fonction, et le plus souvent ce n'est pas ce que vous voulez!. Voir JsFiddle: 3 instances sont producting seulement 1 entrée de journal à l'échelle mondiale.
Vous devez créer un sans rebond fonction pour chaque instance de composant, et pas un seul sans rebond de la fonction au niveau de la classe, partagée par chaque instance de composant.
Prendre soin de Réagir à l'événement de mise en commun
Cela est lié parce que nous voulons souvent anti-rebond ou de gaz d'événements DOM.
À Réagir, le cas des objets (c'est à dire,
SyntheticEvent
) que vous recevez des rappels sont mis en commun (c'est maintenant documenté). Cela signifie que, après l'événement de rappel a appelé, le SyntheticEvent que vous recevrez sera remis dans la piscine avec des attributs vides pour réduire la GC pression.Donc, si vous avez accès
SyntheticEvent
propriétés de manière asynchrone à l'origine de rappel (comme cela peut être le cas si vous accélération/anti-rebond), les propriétés que vous avez accès peuvent être effacées. Si vous souhaitez que l'événement à ne jamais se remettre dans la piscine, vous pouvez utiliser lepersist()
méthode.Sans persistent (comportement par défaut: l'événement)
Le 2ème (async) va imprimer
hasNativeEvent=false
parce que les propriétés de l'événement ont été nettoyés.Avec persistent
Le 2ème (async) va imprimer
hasNativeEvent=true
parce quepersist
vous permet d'éviter de placer l'événement dans la piscine.Vous pouvez tester ces 2 comportements ici: JsFiddle
Lire Julen réponse pour un exemple d'utilisation de
persist()
avec une manette des gaz/fonction anti-rebond.handleOnChange = debounce((e) => { /* onChange handler code here */ }, timeout)
au plus haut niveau de votre classe. Vous êtes encore à établir effectivement un membre de l'instance mais il a l'air un peu plus comme une méthode normale de définition. Pas besoin d'unconstructor
si vous n'avez pas encore défini. Je suppose que c'est surtout un style de préférence.componentWillUnmount
:this.method.cancel()
- sinon, il pourrait vouloir setState sur une démonté composant.this.method = debounce(this.method,1000);
ne devraient pas travailler. Vous devez lier cette méthode pour cette (sic!):this.method = debounce(this.method.bind(this),1000);
e.persist()
de fuite de mémoire? Avez-vous besoin pour gérer GC ici manuellement? Si oui, ce qui est une bonne façon de le faire?const [inputText, searchStarwarsHero] = useState('');
searchStarwarsHero
est pas défini dans votre code. Pouvez-vous vérifier de nouveau?Incontrôlée Des Composants
Vous pouvez utiliser le
événement.persist()
méthode.Un exemple qui suit à l'aide de souligner l'
_.debounce()
:Edit: Voir cette JSFiddle
Les Composants Commandés
Mise à jour: l'exemple ci-dessus montre une incontrôlée de la composante. Je contrôlée des éléments de tous les temps, donc voici un autre exemple de la ci-dessus, mais sans l'aide de la
event.persist()
"supercherie".Un JSFiddle est disponible ainsi. Exemple sans trait de soulignement
Edit: mise à jour des exemples et JSFiddles de Réagir 0.12
Edit: mise à jour des exemples afin de répondre à la question soulevée par Sébastien Lorber
Edit: mis à jour avec jsfiddle qui n'utilise pas un trait de soulignement et les utilisations de la plaine javascript anti-rebond.
<input value={this.props.someprop}...
alors il ne rend pas correctement la mise à jour sur pression de touche n'a pas de retour dans le composant jusqu'à ce que après l'anti-rebond. C'est bien d'omettre levalue=
si vous êtes heureux pour que cela soit géré, mais si vous souhaitez pré-remplir la valeur et/ou lier d'ailleurs alors évidemment, cela ne fonctionne pas.onChange : Event -> unit
prend un événement, de sorte que vous pouvez vous débarrasser dethis.refs.searchBox.getDOMNode().value
et de le remplacer avecevt.target.value
pour plus d'ideomatic code javascript.e.persist()
doit aller dans un non-sans rebond de gestionnaire d'événements. Votre exemple devrait ressembler à jsfiddle.net/oza88dye. Pour en savoir plus, vous pouvez consulter la documentation sur Réagir à l'événement de mise en commun{...this.props}
à laSearchBox.render(<input {...this.props}>
de sorte que vous pouvez faire des choses comme<SearchBox className="foo" ...
persist
surtout quand il peut y avoir de nombreux événements, comme surmousemove
. J'ai vu du code de devenir complètement insensible de cette façon. Il est beaucoup plus efficace pour extraire les données nécessaires à partir de la maternelle de la manifestation en cas d'appel, puis appel de la sans rebond / étranglé fonction avec les données uniquement, et NON l'événement lui-même. Pas besoin de persister l'événement de cette façonevent.target.value
est toujours vide pour moi quand j'utiliseevent.persist()
Si vous avez besoin de l'objet événement est d'obtenir le DOM élément d'entrée, la solution est beaucoup plus simple – il suffit d'utiliser
ref
. À noter que cela nécessite Trait de soulignement:J'ai trouvé ce post par Justin Tulk très utile. Après quelques tentatives, dans ce que l'on perçoit le plus de manière officielle à réagir/redux, il montre qu'il échoue en raison de Réagir synthétique de cas de mise en commun. Sa solution, puis utilise une partie de l'état interne de suivre la valeur changé/entré dans l'entrée, avec un rappel à droite après
setState
qui appelle une étranglé/sans rebond redux action qui montre quelques résultats en temps réel.Après avoir lutté avec le texte des entrées pour un certain temps et ne pas trouver un solution parfaite à mon propre compte, j'ai trouvé ceci sur npm: réagir-anti-rebond-entrée.
Voici un exemple simple:
La DebounceInput composant accepte tous les accessoires que vous pouvez affecter à une normale de l'élément d'entrée. Essayer sur codepen
J'espère que cela aide quelqu'un d'autre aussi, et leur permet de gagner du temps.
Si vous utilisez redux vous pouvez le faire dans un moyen très élégant avec middleware. Vous pouvez définir un
Debounce
middleware comme:Vous pouvez ensuite ajouter de l'anti-rebond à l'action des créateurs, tels que:
Il y a en fait déjà middleware vous pouvez descendre de mnp de le faire pour vous.
applyMiddleware(...)
chaîne si nous avons de nombreuxBeaucoup de bonnes infos ici déjà, mais pour être bref. Cela fonctionne pour moi...
_debounce
wrapper il fonctionne. J'adore cette idée!À l'aide de ES6 CLASSE et Réagir 15.x.x & lodash.anti-rebond
Im en utilisant Réagir de refs ici depuis événement pertes de la ce se lier à l'interne.
JS:
HTML:
Vous pouvez utiliser Lodash antirebond https://lodash.com/docs/4.17.5#debounce méthode. C'est simple et efficace.
Vous pouvez également annuler l'anti-rebond de la méthode en utilisant la méthode ci-dessous.
Espère que cela vous aide. Cheers!!
FYI
Voici un autre Opc de mise en œuvre:
J'espère que cela aide 🙂
Avec
debounce
vous avez besoin de garder l'original synthétique événement autour avecevent.persist()
. Voici un exemple fonctionnel testé avecReact 16+
.Avec composante fonctionnelle, vous pouvez le faire -
Références -
- https://gist.github.com/elijahmanor/08fc6c8468c994c844213e4a4344a709
- https://blog.revathskumar.com/2016/02/reactjs-using-debounce-in-react-components.html
2019: Utiliser le "useCallback' réagir crochet
Après avoir essayé de nombreuses approches différentes, j'ai trouvé à l'aide de 'useCallback", pour être le plus simple et le plus efficace pour résoudre les multiples appels au problème de l'utilisation des anti-rebond à l'intérieur d'un événement onChange.
Que par la Les crochets de la documentation de l'API, "useCallback renvoie une mémorisé version de la fonction de rappel qui change seulement si l'une des dépendances a changé."
En passant un tableau vide de dépendance permet de s'assurer que la fonction de rappel est appelée qu'une seule fois. Voici une mise en œuvre simple.
Espérons que cette aide!
Juste une autre variante récente de réagir et de lodash.
Il y a un
use-debounce
package que vous pouvez utiliser avec ReactJS crochets.De colis README:
Comme vous pouvez le voir dans l'exemple ci-dessus, il est configuré pour mettre à jour la variable
value
qu'une seule fois chaque seconde (1000 millisecondes).Au lieu d'emballage de la handleOnChange dans un anti-rebond(), pourquoi ne pas envelopper l'appel ajax à l'intérieur de la fonction de rappel à l'intérieur de l'anti-rebond, afin de ne pas détruire l'objet d'événement. Donc quelque chose comme ceci:
Ici est un exemple, je suis venu avec qui encapsule une autre classe avec un debouncer. Cela se prête bien à être faite dans un décorateur/ordre supérieur de la fonction:
Une belle et propre solution, qui ne nécessite pas de dépendances externes:
L'anti-rebond avec Crochets Réagir
Il utilise une coutume plus la useEffect Réagir crochets et les
setTimeout
/clearTimeout
méthode.J'étais à la recherche d'une solution au même problème et suis tombé sur ce fil ainsi que quelques autres, mais ils avaient le même problème: si vous essayez de faire un
handleOnChange
fonction et vous avez besoin de la valeur à partir d'une cible de l'événement, vous obtiendrezcannot read property value of null
ou quelque erreur. Dans mon cas, j'ai également nécessaire pour préserver le cadre dethis
sans rebond à l'intérieur de la fonction, puisque je suis l'exécution d'une fluxible action. Voici ma solution fonctionne bien pour mon cas d'utilisation, donc je vais la laisser ici au cas où quelqu'un tombe sur ce fil:pour
throttle
oudebounce
le meilleur moyen est de créer une fonction de créateur, de sorte que vous pouvez l'utiliser n'importe où, par exemple:et dans votre
render
méthode que vous pouvez faire:la
updateUserProfileField
méthode permet de créer un coin de la fonction à chaque fois que vous l'appelez.Note n'essayez pas de retourner le gestionnaire directement par exemple, cela ne fonctionnera pas:
la raison pour laquelle cela ne fonctionne pas, car cela va générer une nouvelle accélération de la fonction à chaque fois que l'événement appelé au lieu d'utiliser la même fonction de l'accélérateur, donc, fondamentalement, la puissance sera inutile 😉
Aussi, si vous utilisez
debounce
outhrottle
vous n'avez pas besoinsetTimeout
ouclearTimeout
, c'est pourquoi nous les utilisons 😛Voici un travail Tapuscrit exemple pour ceux qui utilisent TS et souhaitez antirebond
async
fonctions.un peu de retard ici, mais cela devrait vous aider.
créez cette classe(c'est écrit en caractères d'imprimerie, mais il est facile de le convertir en javascript)
et à utiliser
vous pouvez utiliser tlence tlence
Julen solution est un peu difficile à lire, ici, est plus clair et à-le-point de réagir code pour quelqu'un qui a trébuché lui, basée sur le titre et pas les plus petits détails de la question.
tl;dr version: lorsque vous devez mettre à jour les observateurs appel envoyer un calendrier plutôt la méthode qui sera réellement informer les observateurs (ou effectuer ajax, etc)
Complète jsfiddle avec l'exemple de composant jsfiddle
Éviter d'utiliser
event.persist()
- vous voulez laisser Réagir recycler le synthétique de l'événement. Je pense que la meilleure façon de savoir si vous utilisez des classes ou des crochets est de séparer la fonction de rappel en deux morceaux:Classes
Fonctions
Notez que si votre
handleMouseOver
fonction utilise l'état de l'intérieur du composant, vous devez utiliseruseMemo
au lieu deuseRef
et de transmettre ces dépendances sinon vous allez travailler avec des données périmées (ne s'applique pas aux classes de cours).Vous pouvez également utiliser un auto-écrit mixin, quelque chose comme ceci:
Et ensuite l'utiliser dans votre composant comme ceci: