Feature request: scroll restoration

Aperta
#300 15 commenti 17 reazioni 0 assegnatari Vedi su GitHub

Nessuno ha ancora preso questa issue.

Valutazione

Difficoltà
5/5
Tempo stimato
Più di una settimana
Idoneità per principianti
32/100
Tipo di issue
Funzionalità
Chiarezza
Abbastanza chiara
Stato di attività
Ferma
Stack tecnologico
react, typescript
Ambito
frontend, web-dev

Direzione di ricerca

Inizia leggendo l'integrazione di useLocation e l'implementazione collegata di React Router per scroll-restoration. Traccia come navigation, history.state, pagehide e le opzioni dei link o di navigate vengono esposte in wouter. Il lavoro è completo quando una funzionalità mirata di scroll-restoration supporta il reset per le nuove pagine, il ripristino con back/forward, la gestione degli anchor e la possibilità di opt-out senza appesantire il core.

Scritto dal modello di indicizzazione a partire dal testo della issue.

Descrizione

feature

This has been requested before: #132, (partially) #166, #189 - but the suggested code is an incomplete solution:

import { useEffect } from "react";
import { useLocation } from "wouter";

export default function ScrollToTop() {
  const [ pathname ] = useLocation();

  useEffect(() => {
    window.scrollTo(0, 0);
  }, [pathname]);

  return null;
}

This will scroll to the top of the page on any navigation, including when the user presses the back / forward history buttons, and when the user navigates in ways that only affect part of the page (e.g. changing a tab component which records the current tab in the URL). It will also have a brief flicker due to using useEffect rather than useLayoutEffect. A more complete solution would only reset the scroll position when navigating to new pages, restoring previous positions when navigating forward / back, and allowing an override on links to disable scrolling to the top of the page.

React Router provides this as a separate component, but with some necessary integration with the core. That seems like a reasonable approach to follow here too, since it fits the philosophy of not bloating the core library (saving space for people who don't need the feature).

https://reactrouter.com/en/main/components/scroll-restoration

Their (MIT licensed) code shows that there are quite a few considerations here, so it seems beneficial to offer this in the library rather than having each user recreate the functionality for themselves. This will also make it possible to add integrations such as allowing specific links to bypass the scrolling behaviour.

Generally, their approach:

  • takes over the native scroll behaviour (i.e. when the whole page actually switches) by setting history.scrollRestoration (docs)
  • listens for the pagehide event to capture current scroll position before navigating to another page (also captures refreshing) (docs)
  • stores scroll locations in session storage (likely to avoid taking over the state parameter used in the history API)
  • provides a custom implementation of scrolling to anchor elements (likely due to disabling the browser's native handling; this might not be required, but worth finding out what the disadvantages are of allowing native scroll handling)
  • gives links / navigate the ability to bypass auto-scrolling by setting a flag
  • updates the scroll position inside a useLayoutEffect call to avoid flickering that useEffect would cause.

I think a minimal approach could:

  • listen for pagehide events to capture scroll position
  • record this position in the history API for the current page (by calling history.replaceState) - this can be put into the state object since currently it's always just set to null, which avoids the need to use session storage [edit: actually this probably won't work because by the time pagehide fires, the history has (probably?) already updated, so using session storage might be a requirement]
  • set up a useLayoutEffect with useLocation()[0] as a dep. Internally this can check history.state to see if it needs to scroll
    • it would be better if this could depend on the history.state object directly - would it be possible to expose this from useLocation somehow?
Lingua principale
TypeScript
Stelle
7.9k
Fork
194
Merge medio
9m
PR unite (30g)
1

Preparare l'ambiente

Questo progetto non fornisce container di sviluppo, Dockerfile né guida per i contributori, quindi l'ambiente è a tuo carico: parti dal suo README e consulta la nostra guida al primo contributo per i passaggi generali.

Come iniziare

  1. Leggi tutta la issue e poi la guida ai contributi del progetto.
  2. Commenta sulla issue per dire che te ne occupi tu — evita che due persone facciano lo stesso lavoro.
  3. Fai un fork del repository e lavora su un branch.
  4. Apri una pull request che faccia riferimento al numero della issue.

Altre issue di molefrog/wouter

Tutte le issue di molefrog/wouter

Issue simili

Altre issue su TypeScript

Ricevi le nuove issue nella tua casella

Un breve riepilogo di issue GitHub adatte ai principianti.