GOOGLE ADS

lundi 25 avril 2022

Utilisation d'une référence pour rechercher et faire défiler jusqu'à la position supérieure de l'élément enfant dans React

J'espère que mon approche est correcte, mais j'essaie de créer un composant dans React où un tas de publications sont rendues dans une vue en colonne empilées les unes sur les autres, chaque publication individuelle est définie sur 100vh.

Code pseudo

<container ref={postRef}>
<post 1/>
<post 2/>
<post 3/>
</container>

J'ai un refsur le <container/>et à partir de la fonction d'un autre composant, onClickj'obtiens l'index actuel du <post/>sur lequel j'ai cliqué, puis je trouve cet élément dans le dom.

 useEffect(() => {
if (postRef.current && indexOfClickedPost) {
const refBounds = postRef.current.children[indexOfClickedPost].getBoundingClientRect()
window.scrollTo({
top: // which unit goes here?
});
}
})

mon objectif final est de faire défiler mon <container/>composant tout en haut du message par rapport à celui sur lequel on vient de cliquer.

Ex. si l'utilisateur clique sur une publication avec un index de 2, la page défilera jusqu'à l'endroit où la publication 2 div commence

Je ne sais pas quelle unité je dois mettre dans mon window.scrollTopour obtenir cet effet. Mettre refBounds.topne donne pas les résultats que je veux, il semble ne rien faire du tout d'après ce que je peux voir visiblement. Tout conseil serait bon. Merci!


Solution du problème

Je propose deux approches différentes, la première suit votre essai, et elle utilise getBoundingClientRect()pour calculer la bonne distance à partir du haut et scrollTofaire défiler jusqu'à cet élément :

function App() {
const [currPostIdx, setCurrPostIdx] = useState(0);
const containerRef = useRef();
const selectPost = (idx) => {
setCurrPostIdx(idx);
};
useEffect(() => {
const el = containerRef.current.children[currPostIdx];
const top = window.pageYOffset + el.getBoundingClientRect().top;
console.log(currPostIdx, top);
window.scrollTo(0, top);
}, [currPostIdx]);
return (
<>
<ul className="navbar">
{posts.map((p, i) => (
<li key={p.title} onClick={() => selectPost(i)}>
{p.title}
</li>
))}
</ul>
<div ref={containerRef}>
{posts.map((p, idx) => (
<Post key={p.title} post={p} idx={idx} />
))}
</div>
</>
);
}
const Post = ({ idx, post }) => (
<div
id={post.title}
className="post"
style={{ backgroundColor: `#${idx + 5}${idx * 3}${idx * 4}` }}
>
<h4>{post.title}</h4>
</div>
);

Démo ICI

La deuxième approche utilise la navigation par hachage et n'a donc pas à calculer manuellement la position de l'élément :

function App() {
return (
<div>
<div className="navbar">
{posts.map((p) => (
<a href={`#${p.title}`}>{p.title}</a>
))}
</div>
{posts.map((p, idx) => (
<Post key={p.title} post={p} idx={idx} />
))}
</div>
);
}
const Post = ({ idx, post }) => (
<div
id={post.title}
className="post"
style={{ backgroundColor: `#${idx + 5}${idx * 3}${idx * 4}` }}
>
<h4>{post.title}</h4>
</div>
);

Démo ICI

Aucun commentaire:

Enregistrer un commentaire

Comment utiliseriez-vous .reduce() sur des arguments au lieu d'un tableau ou d'un objet spécifique&nbsp;?

Je veux définir une fonction.flatten qui aplatit plusieurs éléments en un seul tableau. Je sais que ce qui suit n'est pas possible, mais...