Scrollen Sie in die Ansicht, um zu reagieren
Ich mache eine einfache Reaktions-App, in der es zwei verschiedene gibt div's
.
Eine mit Auswahleingabe und ausgewählter Liste,
<div id="container">
<div className="_2iA8p44d0WZ">
<span className="chip _7ahQImy">Item One</span>
<span className="chip _7ahQImy">Item Two</span>
<span className="chip _7ahQImy">Item Three</span>
<span className="chip _7ahQImy">Item Four</span>
<span className="chip _7ahQImy">Item Five</span>
<input
type="text"
className="searchBox"
id="search_input"
placeholder="Select"
autoComplete="off"
value=""
/>
</div>
</div>
Ein anderer wird die gewählte Option Liste unten als fieldset
,
<div>
{selectedElements.map((item, i) => (
<div key={i} className="selected-element" ref={scrollDiv}>
<fieldset>
<legend>{item}</legend>
</fieldset>
</div>
))}
</div>
Basierend auf dieser Lösung habe ich createRef
dem ausgewählten Element Folgendes hinzugefügt :
<div key={i} className="selected-element" ref={scrollDiv}>
</div>
Dann habe ich Javascript-Abfragemethoden verwendet, um DOM-Elemente wie:
const chipsArray = document.querySelectorAll("#container > div > .chip");
Klickereignis-Listener zu allen Elementen wie hinzugefügt,
chipsArray.forEach((elem, index) => {
elem.addEventListener("click", scrollSmoothHandler);
});
Dann scrollSmoothHandler
wie,
const scrollDiv = createRef();
const scrollSmoothHandler = () => {
console.log(scrollDiv.current);
if (scrollDiv.current) {
scrollDiv.current.scrollIntoView({ behavior: "smooth" });
}
};
Dies funktioniert jedoch nicht wie erwartet.
Anforderung:
first div
Wenn Sie auf ein Element in klicken , muss das zugehörige Feldset smooth scrolled
in ein anderes Div gelangen.
Beispiel: Wenn der Benutzer auf das Element Item Four
unter klickt<div id="container"> ... <span className="chip _7ahQImy">Item Four</span> ... </div>
dann muss das zugehörige Feldset gescrollt werden. Hier das Feldset mit Legende als Item Four
..
Ich denke auch, dass die js dom-Abfragemethoden reagieren und es scheint keine reaktive Art der Implementierung zu sein. Kann mir bitte jemand helfen, das Ergebnis des Bildlaufs zu einem verwandten Feldsatz zu erzielen, indem Sie auf das ausgewählte Element klicken.
Antworten
Problem
React.createRef
ist wirklich nur in klassenbasierten Komponenten gültig. Bei Verwendung in einem Funktionskomponentenkörper wird der Verweis bei jedem Renderzyklus neu erstellt.- Verwenden Sie keinen DOM-Abfrageselektor, um
onClick
Listener an DOM-Elemente anzuhängen . Diese leben draußen und Sie müssen daran denken, sie zu bereinigen (dh zu entfernen), damit Sie keinen Speicherverlust haben. Verwenden Sie dieonClick
Requisite von React . - Wenn die zugeordnet
selectedElements
sind, fügen Sie jedem Element den gleichen Verweis hinzu, sodass der letzte Satz derjenige ist, den Ihre Benutzeroberfläche erhält.
Lösung
- Verwenden Sie diese
React.useRef
Funktion im Funktionskomponentenkörper, um ein Array von Reaktionsreferenzen zu speichern, die an jedes Element angehängt werden sollen, in das Sie scrollen möchten. - Bringen Sie die
scrollSmoothHandler
direkt an den jeweiligenspan
s‘onClick
prop. - Fügen Sie jede Referenz aus dem in 1. erstellten Referenzarray jedem zugeordneten Feldsatz hinzu, zu dem Sie einen Bildlauf durchführen möchten.
Code
import React, { createRef, useRef } from "react";
import { render } from "react-dom";
const App = () => {
const selectedElements = [
"Item One",
"Item Two",
"Item Three",
"Item Four",
"Item Five"
];
// React ref to store array of refs
const scrollRefs = useRef([]);
// Populate scrollable refs, only create them once
// if the selectedElements array length is expected to change there is a workaround
scrollRefs.current = [...Array(selectedElements.length).keys()].map(
(_, i) => scrollRefs.current[i] ?? createRef()
);
// Curried handler to take index and return click handler
const scrollSmoothHandler = (index) => () => {
scrollRefs.current[index].current.scrollIntoView({ behavior: "smooth" });
};
return (
<div>
<div id="container">
<div className="_2iA8p44d0WZ">
{selectedElements.map((el, i) => (
<span
className="chip _7ahQImy"
onClick={scrollSmoothHandler(i)} // <-- pass index to curried handler
>
{el}
</span>
))}
<input
type="text"
className="searchBox"
id="search_input"
placeholder="Select"
autoComplete="off"
value=""
/>
</div>
</div>
<div>
{selectedElements.map((item, i) => (
<div
key={i}
className="selected-element"
ref={scrollRefs.current[i]} // <-- pass scroll ref @ index i
>
<fieldset>
<legend>{item}</legend>
</fieldset>
</div>
))}
</div>
</div>
);
};
Lösung Nr. 2
Da Sie keine Elemente im div
with aktualisieren können id="container"
und alle onClick
Handler über die Abfrage des DOM angehängt werden müssen, können Sie weiterhin einen Curry- scrollSmoothHandler
Rückruf verwenden und einen Index in den Bereich einschließen. Sie benötigen einen useEffect
Hook, um das DOM nach dem ersten Rendern abzufragen , damit die Bereiche bereitgestellt wurden, und einen useState
Hook, um einen "geladenen" Status zu speichern. Der Status ist erforderlich, um ein erneutes Rendern auszulösen und das scrollRefs
im scrollSmoothHandler
Rückruf wieder einzuschließen .
const App = () => {
const selectedElements = [
"Item One",
"Item Two",
"Item Three",
"Item Four",
"Item Five"
];
const [loaded, setLoaded] = useState(false);
const scrollRefs = useRef([]);
const scrollSmoothHandler = (index) => () => {
scrollRefs.current[index].current.scrollIntoView({ behavior: "smooth" });
};
useEffect(() => {
const chipsArray = document.querySelectorAll("#container > div > .chip");
if (!loaded) {
scrollRefs.current = [...Array(chipsArray.length).keys()].map(
(_, i) => scrollRefs.current[i] ?? createRef()
);
chipsArray.forEach((elem, index) => {
elem.addEventListener("click", scrollSmoothHandler(index));
});
setLoaded(true);
}
}, [loaded]);
return (
<div>
<div id="container">
<div className="_2iA8p44d0WZ">
<span className="chip _7ahQImy">Item One</span>
<span className="chip _7ahQImy">Item Two</span>
<span className="chip _7ahQImy">Item Three</span>
<span className="chip _7ahQImy">Item Four</span>
<span className="chip _7ahQImy">Item Five</span>
<input
type="text"
className="searchBox"
id="search_input"
placeholder="Select"
autoComplete="off"
value=""
/>
</div>
</div>
<div>
{selectedElements.map((item, i) => (
<div key={i} className="selected-element" ref={scrollRefs.current[i]}>
<fieldset>
<legend>{item}</legend>
</fieldset>
</div>
))}
</div>
</div>
);
};