Faites défiler la vue en réagissant
Je crée une application de réaction simple où il y en a deux div's
.
Un avec sélection d'entrée et liste sélectionnée,
<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 autre listera l'option sélectionnée comme suit fieldset
:
<div>
{selectedElements.map((item, i) => (
<div key={i} className="selected-element" ref={scrollDiv}>
<fieldset>
<legend>{item}</legend>
</fieldset>
</div>
))}
</div>
Sur la base de cette solution , j'ai ajouté createRef
à l'élément sélectionné comme,
<div key={i} className="selected-element" ref={scrollDiv}>
</div>
Ensuite, j'ai utilisé des méthodes de requête Javascript pour obtenir des éléments DOM comme,
const chipsArray = document.querySelectorAll("#container > div > .chip");
Ajout d'un écouteur d'événement de clic à tous les éléments comme,
chipsArray.forEach((elem, index) => {
elem.addEventListener("click", scrollSmoothHandler);
});
Alors scrollSmoothHandler
comme,
const scrollDiv = createRef();
const scrollSmoothHandler = () => {
console.log(scrollDiv.current);
if (scrollDiv.current) {
scrollDiv.current.scrollIntoView({ behavior: "smooth" });
}
};
Mais cela ne fonctionne pas comme prévu.
Exigence:
first div
Lorsque vous cliquez sur un élément dans , le jeu de champs associé doit entrer smooth scrolled
dans un autre div.
Par exemple: si l'utilisateur clique sur l'élément Item Four
sous<div id="container"> ... <span className="chip _7ahQImy">Item Four</span> ... </div>
alors le jeu de champs associé doit être défilé. Ici le fieldset avec la légende comme Item Four
..
Je pense aussi faire réagir les méthodes de requête js dom et cela ne semble pas être une manière de réagir. Quelqu'un peut-il s'il vous plaît m'aider à obtenir le résultat du défilement vers un jeu de champs associé en cliquant sur l'élément sélectionné.
Réponses
Problème
React.createRef
n'est vraiment valable que dans les composants basés sur les classes. S'il était utilisé dans un corps de composant fonctionnel, la référence serait recréée à chaque cycle de rendu.- N'utilisez pas de sélecteur de requête DOM pour attacher des
onClick
écouteurs aux éléments DOM. Ceux-ci vivent à l'extérieur et vous devez vous rappeler de les nettoyer (c'est-à-dire de les supprimer) pour ne pas avoir de fuite de mémoire. Utilisez l'onClick
accessoire de React . - Lorsque les
selectedElements
sont mappés, vous attachez la même référence à chaque élément, donc le dernier ensemble est celui que votre interface utilisateur obtient.
Solution
- Utilisez-le
React.useRef
dans le corps du composant fonctionnel pour stocker un tableau de références de réaction à attacher à chaque élément que vous souhaitez afficher. - Fixez le
scrollSmoothHandler
directement à chaquespan
de »onClick
l'hélice. - Attachez chaque référence du tableau de références créé en 1. à chaque jeu de champs mappé vers lequel vous voulez faire défiler.
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>
);
};
Solution n ° 2
Étant donné que vous ne pouvez mettre à jour aucun élément dans le div
avec id="container"
et que tous les onClick
gestionnaires doivent être attachés via l'interrogation du DOM, vous pouvez toujours utiliser un scrollSmoothHandler
rappel curry et inclure un index dans la portée. Vous aurez besoin d'un useEffect
hook pour interroger le DOM après le rendu initial afin que les travées aient été montées, et d'un useState
hook pour stocker un état "chargé". L'état est nécessaire pour déclencher un rerender et recouvrir le scrollRefs
dans le scrollSmoothHandler
callback.
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>
);
};