web-dev-qa-db-fra.com

Utilisez des ancres avec react-router

Comment puis-je utiliser react-router et faire en sorte qu'un lien mette vers un endroit particulier sur une page donnée? (par exemple, /home-page#section-three)

Détails:

J'utilise react-router dans mon application React. 

J'ai une barre de navigation à l'échelle du site qui doit être liée à une partie particulière d'une page, telle que /home-page#section-three

Ainsi, même si vous êtes sur /blog, cliquez sur ce lien pour charger la page d’accueil, la troisième section étant alors affichée. C’est exactement comme cela que fonctionnerait un <a href="/home-page#section-three> standard.

Note: Les créateurs de react-router n'ont pas donné de réponse explicite. Ils disent que c'est en cours et, entre-temps, utilisent les réponses des autres. Je ferai de mon mieux pour garder cette question à jour avec les progrès et les solutions possibles jusqu'à ce qu'une dominante apparaisse.

Recherche:


Comment utiliser les liens d'ancrage normaux avec react-router

Cette question date de 2015 (il y a donc 10 ans, en temps de réaction). La réponse la plus votée dit d'utiliser HistoryLocation au lieu de HashLocation. Fondamentalement, cela signifie stocker l'emplacement dans l'historique de la fenêtre, plutôt que dans le fragment de hachage. 

La mauvaise nouvelle est… Même en utilisant HistoryLocation (ce que la plupart des tutoriels et de la documentation disent de faire en 2016), les balises d'ancrage ne fonctionnent toujours pas.


https://github.com/ReactTraining/react-router/issues/394

Un fil sur ReactTraining sur l'utilisation des liens d'ancrage avec react-router. Ce n'est pas une réponse confirmée. Soyez prudent, car la plupart des réponses proposées sont obsolètes (par exemple, utilisez le "hash" prop dans <Link>)


25
Don P

Voici une solution que j'ai trouvée (octobre 2016). Il est compatible avec plusieurs navigateurs (testé, par exemple, ff, chrome, safari mobile, safari).

Vous pouvez fournir une propriété onUpdate à votre routeur. Ceci est appelé à chaque fois qu'un itinéraire est mis à jour. Cette solution utilise la propriété onUpdate pour vérifier si un élément DOM correspond au hachage, puis la fait défiler à la fin de la transition de la route.

Vous devez utiliser browserHistory et non hashHistory.

La réponse est par "Rafrax" dans ce fil .

Ajoutez ce code à l'endroit où vous définissez <Router>:

import React from 'react';
import { render } from 'react-dom';
import { Router, Route, browserHistory } from 'react-router';

const routes = (
  // your routes
);

function hashLinkScroll() {
  const { hash } = window.location;
  if (hash !== '') {
    // Push onto callback queue so it runs after the DOM is updated,
    // this is required when navigating from a different page so that
    // the element is rendered on the page before trying to getElementById.
    setTimeout(() => {
      const id = hash.replace('#', '');
      const element = document.getElementById(id);
      if (element) element.scrollIntoView();
    }, 0);
  }
}

render(
  <Router
    history={browserHistory}
    routes={routes}
    onUpdate={hashLinkScroll}
  />,
  document.getElementById('root')
)

Si vous vous sentez paresseux et que vous ne voulez pas copier ce code, vous pouvez utiliser Anchorate qui définit simplement cette fonction pour vous. https://github.com/adjohnson916/anchorate

18
Don P

React Router Hash Link a travaillé pour moi. Facile à installer et à mettre en œuvre:

$ npm install --save react-router-hash-link

Dans votre composant.js, importez-le en tant que lien:

import { HashLink as Link } from 'react-router-hash-link';

Et au lieu d'utiliser une ancre <a>, utilisez <Link>:

<Link to="home-page#section-three>Section three</Link>

NOTE: J'ai utilisé HashRouter au lieu de Router:

15
maledr53

Le problème avec https://stackoverflow.com/a/40280486/515585 est parfois l'élément dont l'identifiant est toujours rendu ou chargé si cette section dépend d'une action asynchrone. La fonction suivante essaiera de trouver l'élément par ID, d'y accéder et d'essayer toutes les 100 ms jusqu'à ce qu'il atteigne un maximum de 50 tentatives:

scrollToLocation = () => {
  const { hash } = window.location;
  if (hash !== '') {
    let retries = 0;
    const id = hash.replace('#', '');
    const scroll = () => {
      retries += 0;
      if (retries > 50) return;
      const element = document.getElementById(id);
      if (element) {
        setTimeout(() => element.scrollIntoView(), 0);
      } else {
        setTimeout(scroll, 100);
      }
    };
    scroll();
  }
}
1
randomor

Une alternative: react-scrollchor https://www.npmjs.com/package/react-scrollchor

react-scrollchor: Un composant React pour faire défiler les liens #hash avec des animations fluides. Scrollchor est un mélange de Scroll et d'Anchor

NOTE: Il n'utilise pas de réaction-routeur

1
Ram

Évitez simplement d'utiliser react-router pour le défilement local:

document.getElementById('myElementSomewhere').scrollIntoView() 
1
alex_1948511

J'ai adapté la solution de Don P (voir ci-dessus) au react-router 4 (janvier 2019) car il n'y a plus de variable onUpdate sur <Router>.

import React from 'react';
import * as ReactDOM from 'react-dom';
import { Router, Route } from 'react-router';
import { createBrowserHistory } from 'history';

const browserHistory = createBrowserHistory();

browserHistory.listen(location => {
    const { hash } = location;
    if (hash !== '') {
        // Push onto callback queue so it runs after the DOM is updated,
        // this is required when navigating from a different page so that
        // the element is rendered on the page before trying to getElementById.
        setTimeout(
            () => {
                const id = hash.replace('#', '');
                const element = document.getElementById(id);
                if (element) {
                    element.scrollIntoView();
                }
            },
            0
        );
    }
});

ReactDOM.render(
  <Router history={browserHistory}>
      // insert your routes here...
  />,
  document.getElementById('root')
)
0
Matthias Bohlen