Przewiń do widoku w Reaguj
Tworzę prostą aplikację do reagowania, w której są dwa różne div's
...
Jeden z wybranym wejściem i wybraną listą,
<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>
Inny wyświetli wybraną opcję jako fieldset
,
<div>
{selectedElements.map((item, i) => (
<div key={i} className="selected-element" ref={scrollDiv}>
<fieldset>
<legend>{item}</legend>
</fieldset>
</div>
))}
</div>
Bazując na tym rozwiązaniu dodałem createRef
do wybranego elementu np.
<div key={i} className="selected-element" ref={scrollDiv}>
</div>
Następnie skorzystałem z metod zapytań Javascript, aby uzyskać elementy DOM, takie jak,
const chipsArray = document.querySelectorAll("#container > div > .chip");
Dodano detektor kliknięć do wszystkich elementów, takich jak,
chipsArray.forEach((elem, index) => {
elem.addEventListener("click", scrollSmoothHandler);
});
Następnie scrollSmoothHandler
jak
const scrollDiv = createRef();
const scrollSmoothHandler = () => {
console.log(scrollDiv.current);
if (scrollDiv.current) {
scrollDiv.current.scrollIntoView({ behavior: "smooth" });
}
};
Ale to nie działa zgodnie z oczekiwaniami.
Wymaganie:
Po kliknięciu dowolnego elementu w first div
, powiązany zestaw pól musi przejść smooth scrolled
do innego div.
Np .: Jeśli użytkownik kliknie element Item Four
pod<div id="container"> ... <span className="chip _7ahQImy">Item Four</span> ... </div>
następnie powiązany zestaw pól musi zostać przewinięty do. Tutaj zestaw pól z legendą jako Item Four
...
Myślę również, że wykonanie zapytań js dom metodami na reaguje i wydaje się, że nie jest to reakcja na sposób implementacji. Czy ktoś może mi uprzejmie pomóc w osiągnięciu wyniku przewijania do odpowiedniego zestawu pól po kliknięciu wybranej pozycji.
Odpowiedzi
Kwestia
React.createRef
jest tak naprawdę ważne tylko w komponentach opartych na klasach. Jeśli zostanie użyty w korpusie komponentu funkcjonalnego, ref będzie odtwarzany w każdym cyklu renderowania.- Nie używaj selektora zapytań DOM do dołączania
onClick
detektorów do elementów DOM. Te żyjące na zewnątrz reagują i musisz pamiętać, aby je wyczyścić (tj. Usunąć), aby nie doszło do wycieku pamięci. UżyjonClick
rekwizytu Reacta. - Kiedy
selectedElements
są mapowane, dołączasz ten sam odnośnik do każdego elementu, więc ostatni zestaw jest tym, który dostaje twój interfejs użytkownika.
Rozwiązanie
- Użyj
React.useRef
w treści komponentu funkcjonalnego, aby przechowywać tablicę odwołań do reakcji, które mają być dołączone do każdego elementu, który chcesz przewinąć do widoku. - Mocowanie
scrollSmoothHandler
bezpośrednio do siebiespan
„sonClick
podpory. - Dołącz każdy ref z tablicy ref utworzonej w 1. do każdego odwzorowanego zestawu pól, do którego chcesz przewinąć.
Kod
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>
);
};
Rozwiązanie nr 2
Ponieważ nie możesz aktualizować żadnych elementów w div
with, id="container"
a wszystkie onClick
programy obsługujące muszą być dołączone poprzez zapytanie do DOM, nadal możesz użyć scrollSmoothHandler
wywołania zwrotnego curried i zawrzeć indeks w zakresie. Będziesz potrzebował useEffect
haka do wysyłania zapytań do DOM po początkowym renderowaniu, aby rozpiętości zostały zamontowane, oraz useState
haka do przechowywania stanu „załadowanego”. Stan jest niezbędny do wyzwolenia ponownego wysłania i ponownego zamknięcia scrollRefs
w scrollSmoothHandler
wywołaniu zwrotnym.
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>
);
};