Ich habe in React eine Komponente erstellt, die ihren eigenen Stil beim Scrollen im Fenster aktualisieren soll, um einen Parallaxeeffekt zu erzeugen.
Die Komponentenmethode render
sieht folgendermaßen aus:
function() {
let style = { transform: 'translateY(0px)' };
window.addEventListener('scroll', (event) => {
let scrollTop = event.srcElement.body.scrollTop,
itemTranslate = Math.min(0, scrollTop/3 - 60);
style.transform = 'translateY(' + itemTranslate + 'px)');
});
return (
<div style={style}></div>
);
}
Dies funktioniert nicht, da React nicht weiß, dass sich die Komponente geändert hat, und daher die Komponente nicht erneut gerendert wird.
Ich habe versucht, den Wert von itemTranslate
im Status der Komponente zu speichern und setState
den Scroll-Rückruf aufzurufen . Dies macht das Scrollen jedoch unbrauchbar, da dies sehr langsam ist.
Irgendwelche Vorschläge, wie das geht?
javascript
reactjs
Alejandro Pérez
quelle
quelle
render
im selben Thread aufrufen ) sollten sich nur mit der Logik befassen, die sich auf das Rendern / Aktualisieren des tatsächlichen DOM in React bezieht. Stattdessen sollten Sie, wie von @AustinGreco unten gezeigt, die angegebenen React-Lebenszyklusmethoden verwenden, um Ihre Ereignisbindung zu erstellen und zu entfernen. Dies macht es in der Komponente in sich geschlossen und stellt sicher, dass kein Leck auftritt, indem sichergestellt wird, dass die Ereignisbindung entfernt wird, wenn die Komponente, die sie verwendet, nicht gemountet ist.Antworten:
Sie sollten den Listener einbinden
componentDidMount
, auf diese Weise wird er nur einmal erstellt. Sie sollten in der Lage sein, den Stil im Status zu speichern. Der Listener war wahrscheinlich die Ursache für Leistungsprobleme.Etwas wie das:
quelle
this.handleScroll = this.handleScroll.bind(this)
binden : Bindet dies innerhalbhandleScroll
der Komponente anstelle des Fensters.event.target.scrollingElement.scrollTop
Sie können dem
onScroll
Ereignis im Element React eine Funktion übergeben : https://facebook.github.io/react/docs/events.html#ui-eventsEine andere Antwort, die ähnlich ist: https://stackoverflow.com/a/36207913/1255973
quelle
Meine Lösung für die Erstellung einer reaktionsschnellen Navigationsleiste (Position: 'relativ', wenn nicht gescrollt wird, und fest beim Scrollen und nicht oben auf der Seite)
Keine Leistungsprobleme für mich.
quelle
Um allen hier zu helfen, die die verzögerten Verhaltens- / Leistungsprobleme bei der Verwendung der Austins-Antwort bemerkt haben und ein Beispiel mit den in den Kommentaren erwähnten Refs wünschen, ist hier ein Beispiel, das ich zum Umschalten einer Klasse für ein Bildlauf-Auf / Ab-Symbol verwendet habe:
In der Rendermethode:
In der Handler-Methode:
Und fügen Sie Ihre Handler auf die gleiche Weise wie in Austin hinzu / entfernen Sie sie:
Dokumente auf den Refs .
quelle
this.scrollIcon.className = whatever-you-want
.className
oderclassList
. Außerdem brauchte ich nichtwindow.addEventListener()
: Ich habe nur React's verwendetonScroll
und es ist so schnell, solange Sie Requisiten / Status nicht aktualisieren!Ich habe festgestellt, dass ich den Ereignis-Listener nur dann erfolgreich hinzufügen kann, wenn ich true wie folgt übergebe:
quelle
userCapture
: Optional. Ein boolescher Wert, der angibt, ob das Ereignis in der Erfassungs- oder in der Blasenphase ausgeführt werden soll. Mögliche Werte: true - Der Ereignishandler wird in der Erfassungsphase false- Default ausgeführt. Der Event-Handler wird in der Blasenphase ausgeführtEin Beispiel mit classNames , React hooks useEffect , useState und styled-jsx :
quelle
mit Haken
quelle
Beispiel für eine Funktionskomponente mit useEffect:
Hinweis : Sie müssen den Ereignis-Listener entfernen, indem Sie in useEffect eine "Bereinigungs" -Funktion zurückgeben. Wenn Sie dies nicht tun, erhalten Sie jedes Mal, wenn die Komponente aktualisiert wird, einen zusätzlichen Fenster-Scroll-Listener.
quelle
Wenn Sie an einer untergeordneten Komponente interessiert sind, die einen Bildlauf durchführt, kann dieses Beispiel hilfreich sein: https://codepen.io/JohnReynolds57/pen/NLNOyO?editors=0011
quelle
Ich habe das Problem durch die Verwendung und Änderung von CSS-Variablen gelöst. Auf diese Weise muss ich den Komponentenstatus nicht ändern, was zu Leistungsproblemen führt.
index.css
Navbar.jsx
Navbar.module.css
quelle
Meine Wette hier ist die Verwendung von Funktionskomponenten mit neuen Hooks, um das Problem zu lösen, aber anstatt
useEffect
wie in den vorherigen Antworten zu verwenden, denke ich, dass die richtige OptionuseLayoutEffect
aus einem wichtigen Grund wäre:Dies finden Sie in der React-Dokumentation . Wenn wir
useEffect
stattdessen verwenden und die bereits gescrollte Seite neu laden, ist das Scrollen falsch und unsere Klasse wird nicht angewendet, was zu einem unerwünschten Verhalten führt.Ein Beispiel:
Eine mögliche Lösung für das Problem könnte https://codepen.io/dcalderon/pen/mdJzOYq sein
quelle
useLayoutEffect
. Ich versuche zu sehen, was Sie erwähnt haben.useEffect
hier im Vergleich zu als Problem erwähnt habenuseLayoutEffect
..Header--scrolled
manchmal eine Klasse.Header--scrolledLayout
angewendet wird, aber dank useLayoutEffect wird 100% richtig angewendet.Hier ist ein weiteres Beispiel mit HOOKS fontAwesomeIcon und Kendo UI React
[! [Screenshot hier] [1]] [1]
quelle
Update für eine Antwort mit React Hooks
Dies sind zwei Haken - einer für die Richtung (oben / unten / keine) und einer für die tatsächliche Position
Verwenden Sie wie folgt:
Hier sind die Haken:
quelle
Um die Antwort von @ Austin zu erweitern, sollten Sie
this.handleScroll = this.handleScroll.bind(this)
Ihrem Konstruktor Folgendes hinzufügen :Dies gibt
handleScroll()
Zugriff auf den richtigen Bereich, wenn es vom Ereignis-Listener aufgerufen wird.Beachten Sie auch, dass Sie
.bind(this)
die Methoden inaddEventListener
oderremoveEventListener
nicht ausführen können, da sie jeweils Verweise auf verschiedene Funktionen zurückgeben und das Ereignis beim Entfernen der Komponente nicht entfernt wird.quelle