Last active
August 29, 2023 07:43
-
-
Save wchargin/aa15c01909e613eaa0c693be11f4b615 to your computer and use it in GitHub Desktop.
telescroll: trigger a scroll event in the future
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import { createContext, useContext, useRef } from "react"; | |
const TelescrollContext = createContext({ | |
provideScroll: () => {}, | |
requestScroll: () => {}, | |
}); | |
export function TelescrollProvider({ children }) { | |
const requested = useRef(null); | |
function provideScroll(key) { | |
return (el) => { | |
if (requested.current === key) { | |
el.scrollIntoView(); | |
requested.current = null; | |
} | |
}; | |
} | |
function requestScroll(key) { | |
if (typeof key !== "string") throw new Error("Invalid scroll key: " + key); | |
requested.current = key; | |
// TODO: When/how can we unregister a scroll that isn't triggered? | |
} | |
return ( | |
<TelescrollContext.Provider value={{ provideScroll, requestScroll }}> | |
{children} | |
</TelescrollContext.Provider> | |
); | |
} | |
export function useTelescroll() { | |
return useContext(TelescrollContext); | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// A detail page for an item, including a link back to the main page. The main | |
// page has very many items, so we'd like to load it and scroll so that the | |
// view includes the item that we just came from. Use `requestScroll`. | |
function DetailPage({ id }) { | |
const { requestScroll } = useTelescroll(); | |
return ( | |
<main> | |
<h1>Item details</h1> | |
<p>...</p> | |
<Link to="/" onClick={() => requestScroll(`item-${id}`)}> | |
Back to main page | |
</Link> | |
</main> | |
); | |
} | |
// A main page, with many item overviews. Each uses `provideScroll` to allow | |
// other pages to scroll into it. | |
function MainPage() { | |
const { provideScroll } = useTelescroll(); | |
const items = getAllTheItems(); | |
return ( | |
<main> | |
<h1>All the items</h1> | |
{items.map((item) => ( | |
<div key={item.id} ref={provideScroll(`item-${id}`)}> | |
<h2>Item #{item.id}</h2> | |
<p>{item.description}</p> | |
<p> | |
<Link to={`/item/${item.id}`}>More details…</Link> | |
</p> | |
</div> | |
))} | |
</main> | |
); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment