Comments (11)
I'm trying to wrap my head around this project, so thanks in advance for being patient.
Is this issue saying that
- We want to know the scroll position for the previous location object?
- We want to provide the initial scroll position for the next location object?
- Both?
from history.
Hi @ericlynnpeterson! Thank you for taking a look :)
It may help to think about it like this: The location
object tells you at any given point in time where you are. Currently, the pathname, search string, and state are all part of that object. They all answer the question "where am I?"
All we want to do here is add scroll information to the location
object so it can better answer that question. This will most likely involve two parts:
- Use
getScrollPosition
to record the scroll information immediately before we change the URL - Include the
scrollX
andscrollY
properties in thecreateLocation
function
As a side note, createLocation
is getting quite a few arguments. We may want to consider slimming them down into an options object or something...
Does that help?
from history.
Thanks @mjackson. That does help. Maybe a followup question?
- If the
location
object answers the questions "where am I?", with regards to scrolling, do we need to update the currentlocation
object's scrollX and scrollY position on every scroll?
Maybe an example will help.
// Initial Location with scroll position
var history = createHistory({
getScrollPosition() {
return { x: 0, y: 200 };
}
});
// Initial location
{
pathname: '/',
search: '',
state: null,
action: POP,
scrollX: 0,
scrollY: 200 // <-- from getScrollPosition()
}
// Scroll down a bit; updates along the way
{
pathname: '/',
search: '',
state: null,
action: POP,
scrollX: 0,
scrollY: 400
}
// Push a new location
history.pushState(null, '/home');
{
pathname: '/home',
search: '',
state: null,
action: PUSH,
scrollX: 0,
scrollY: 0
// I was thinking that the only time we used the getScrollPosition()
// value was for the initial location. Correct?
}
// Scroll down in the new location a bit; updates along the way
{
pathname: '/home',
search: '',
state: null,
action: PUSH,
scrollX: 0,
scrollY: 300
}
// Programatically go back; old location and scroll position are loaded
history.goBack();
{
pathname: '/',
search: '',
state: null,
action: POP,
scrollX: 0,
scrollY: 400 // <-- Last know scroll position for the first location entry
}
Did I get the flow right?
Also, if there is a better place to discuss and ask these questions, point me there. Not sure if these are helpful or just noise inside the Github issue.
from history.
I think the intent is to let you provide something like
var history = createHistory({
getScrollPosition() {
return { x: window.scrollX, y: window.scrollY };
}
});
The reason it's customizable is for mocking, server rendering, and also more complicated setups a la “two different content areas with independent scrolls” or “one overflow: scroll
area somewhere deep in the document”.
do we need to update the current location object's scrollX and scrollY position on every scroll?
You don't need to call getScrollPosition()
and update location
. Consider location
immutable. Once it's created, nobody changes it.
When you call history.pushState()
or similar method, internally, history calls createLocation
:
function pushState(state, path) {
transitionTo(
createLocation(path, state, PUSH, createKey())
);
}
The change is that, with this change, it will also call getScrollPosition()
to remember where we were:
function pushState(state, path) {
transitionTo(
createLocation(path, state, PUSH, createKey(), getScrollPosition())
);
}
This way, when location
object is given to you in the change handler, it has scrollPosition
.
from history.
@gaearon So in your above example, whenever we transition locations, the new location would have a scroll position equal to the result of the getScrollPosition
function we defined in createHistory
?
from history.
the new location would have a scroll position equal to the result of the getScrollPosition function we defined in createHistory?
Almost. We actually want to save the scroll position on the previous location, most likely in sessionStorage
. That way, when you navigate back to that page, we can restore scroll position.
Think about how a browser works. If you're scrolled halfway down a page, and then you navigate somewhere else, and then hit the back button, the browser scrolls down to where you were when you left that page. We want to enable the same functionality in single-page apps.
@gaearon Thanks for chiming in here!
from history.
Just thinking about this a little more...
Maybe all we really need here is a way to update the current location.state
. This is a more generic method that would allow people to store scroll position, among other things. It would work like React's setState
method and do a shallow merge of the object you give it into the current location.state
.
onScroll(function () {
history.setState({ scrollX: 0, scrollY: 0 });
});
This API would skip transitions, so it would be fairly lightweight. If people are concerned about emitting too many location
objects they can either a) limit the number of times they call history.setState
(debounce) or b) perhaps pass a second falsy arg to setState
that indicates that listeners should not be notified.
from history.
Maybe all we really need here is a way to update the current location.state.
Yeah, that's also why I added updateState
to the old branch (remix-run/react-router@a3bb271 followed by remix-run/react-router@b66737f). What's the reason behind using scroll listener instead of recording the position before the next transition though?
The major problem I see with this in general is that we don't get any information about the rendered location like we used to with the router. This can become problematic when rendering asynchronously.
That, and the fact that custom scroll management is inherently error-prone make me think it would be better to not include that functionality in the core. With location.key
it shouldn't be too hard to come up with a standalone utility that provides something like restorePosition(location)
and savePosition(location)
. That way, the user could decide himself when to save and restore the scroll position, depending on what he renders when.
from history.
Yeah, that's why I added updateState
I missed that, @taurose! Sorry, you have to be patient with me. Either that or yell very loud when you do something awesome like that ;)
What's the reason behind using scroll listener instead of recording the position before the next transition though?
My thinking here is that we can be more accurate if we record the scroll position as the page scrolls instead of before the next transition. On popstate
, we don't actually know the URL changed until after it already has. If we try to record the scroll position at that point, we may already be too late. (I'm not sure this is actually a problem. Just guessing...)
The major problem I see with this in general is that we don't get any information about the rendered location like we used to with the router. This can become problematic when rendering asynchronously.
I'm not suggesting we would try and restore scroll position with this module. All setState
would do is give users (like the router) a way to record incremental state changes. It would still be up to the router to determine when to use that information to update the scroll position of the page.
from history.
My thinking here is that we can be more accurate if we record the scroll position as the page scrolls instead of before the next transition.
@mjackson I forgot about that. IIRC, Firefox restores scroll before popstate event. However, I think that the browser scrolling will trigger scroll events as well. Not sure if there's a way to distinguish them from the rest.
I'm not suggesting we would try and restore scroll position with this module. All setState would do is give users (like the router) a way to record incremental state changes.
Oh, I see you said that in your previous comment. Sorry I didn't get that ;)
from history.
I think that the browser scrolling will trigger scroll events as well. Not sure if there's a way to distinguish them from the rest.
Ya, I think we'll have to figure out a good high-level API for this in the router, @taurose. Maybe something like "this is the scrollable element, so only listen for scrolling here". Not sure yet.
from history.
Related Issues (20)
- Named exports don’t work with Node.js ESM support HOT 1
- Sourcemaps are blank HOT 1
- Use History in redux actions HOT 2
- Location type should have template for unknown for state HOT 3
- doing history.go() does NOT trigger a blocker callback handler HOT 1
- Did TS declaration file disappear for v4? HOT 4
- Wrong action after clicking on Forward button in browser HOT 3
- Need history.BackTo(string)
- Is it possible to access the history bundled into React Router? HOT 1
- globalHistory.pushState function excuted failed in baidu.app
- [v6] Missing hashType={"noslash"} of HashRouter HOT 3
- [react-router-dom v6] HashRouter support HOT 1
- Add index property to BrowserHistory, HashHistory and corresponding Update
- Why `history.length` is gone? HOT 7
- createBrowserHistory() breaks history URL on iOS 11
- history
- is this project abandoned? HOT 2
- Navigate replace without generate new location.key
- hash history url is not parsed correctly with query params
- ReferenceError: document is not defined in Next.JS HOT 1
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from history.