Scorri in vista in React
Sto creando una semplice app React dove ce ne sono due differenti div's..
Uno con l'ingresso di selezione e l'elenco selezionato,
<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>
Un altro elencherà l'opzione selezionata come fieldset,
<div>
{selectedElements.map((item, i) => (
<div key={i} className="selected-element" ref={scrollDiv}>
<fieldset>
<legend>{item}</legend>
</fieldset>
</div>
))}
</div>
Sulla base di questa soluzione , ho aggiunto createRefall'elemento selezionato come,
<div key={i} className="selected-element" ref={scrollDiv}>
</div>
Quindi ho utilizzato metodi di query Javascript per ottenere elementi DOM come,
const chipsArray = document.querySelectorAll("#container > div > .chip");
Aggiunto listener di eventi clic a tutti gli elementi come,
chipsArray.forEach((elem, index) => {
elem.addEventListener("click", scrollSmoothHandler);
});
Allora scrollSmoothHandlercome,
const scrollDiv = createRef();
const scrollSmoothHandler = () => {
console.log(scrollDiv.current);
if (scrollDiv.current) {
scrollDiv.current.scrollIntoView({ behavior: "smooth" });
}
};
Ma questo non funziona come previsto.
Requisiti:
Quando si fa clic su qualsiasi elemento in first div, il relativo fieldset deve essere inserito smooth scrolledin un altro div.
Ad esempio: se l'utente fa clic sull'elemento Item Foursotto<div id="container"> ... <span className="chip _7ahQImy">Item Four</span> ... </div>
quindi è necessario scorrere il fieldset correlato. Qui il fieldset con la legenda come Item Four..
Penso che anche rendere i metodi di query js dom su React e non sembra un modo di implementazione React. Qualcuno può aiutarmi gentilmente a ottenere il risultato di scorrere fino a un set di campi correlato facendo clic sull'elemento selezionato ..
Risposte
Problema
React.createRefè veramente valido solo nei componenti basati su classi. Se utilizzato in un corpo di componente funzionale, il riferimento verrebbe ricreato a ogni ciclo di rendering.- Non utilizzare un selettore di query DOM per collegare
onClicklistener agli elementi DOM. Questi vivono fuori reagiscono e dovresti ricordarti di pulirli (cioè rimuoverli) in modo da non avere una perdita di memoria. Usa l'onClickelica di React . - Quando
selectedElementsvengono mappati, si collega lo stesso riferimento a ciascun elemento, quindi l'ultimo set è quello che ottiene la tua interfaccia utente.
Soluzione
- Utilizzare
React.useRefnel corpo del componente funzionale per memorizzare una matrice di riferimenti di reazione da allegare a ciascun elemento che si desidera scorrere nella visualizzazione. - Fissare il
scrollSmoothHandlerdirettamente ad ognispan'sonClickprop. - Associare ogni riferimento dall'array ref creato in 1. a ciascun set di campi mappato a cui si desidera scorrere.
Codice
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>
);
};
Soluzione n. 2
Poiché non è possibile aggiornare alcun elemento nel divwith id="container"e tutti i onClickgestori devono essere collegati tramite query al DOM, è comunque possibile utilizzare una scrollSmoothHandlerrichiamata curry e racchiudere un indice nell'ambito. Avrai bisogno di un useEffecthook per interrogare il DOM dopo il rendering iniziale in modo che gli span siano stati montati e un useStatehook per memorizzare uno stato "caricato". Lo stato è necessario per attivare un rerender e racchiudere di nuovo scrollRefsnel scrollSmoothHandlercallback.
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>
);
};