restore scroll position via history push/replace state - reactjs

i have a list where i can access detail views of my list items.
in my detail views i can navigate betweeen my list items.
i would like to have a back button on the detail view which brings me to my list view no matter how often i navigated in my detail views.
currently i tried this:
i pass a url: string to my navigation component.
thats the url to my list.
then i want to change my state when i click the back button:
const onClickBack = () => {
const stateData = {
path: window.location.href,
scrollTop: 300
}
window.history.replaceState(stateData, "", backURL)
const stateData2 = {
path: window.location.href,
scrollTop: 300
}
window.history.pushState(stateData2, "", backURL)
window.history.back()
}
i copied this code from history pushState and scroll position
no matter how often i navigated, i can go back to my list now. but how can i restore the whole state, e.g. the scroll position?
do i have to pass the whole state object?

It seems like you want to manually restore the scroll position. If this is the case, then you should tell the history API about your intention.
if ('scrollRestoration' in history) {
// Back off, browser, I got this...
history.scrollRestoration = 'manual';
}
This way, the scroll position of the previous URL will remain as well.
docs: https://developers.google.com/web/updates/2015/09/history-api-scroll-restoration

Related

React JS - call function however you get to a page/component

I'm working on a page fetching data and then showing a list of results. I have a main App component with a navbar and 3 possible sub-pages. The first is the home, where you can also do a research as i mentioned. When you do that, i made it so that the beginning of the list scrolls to the top of the browser window (banner, navbar and such get out of the screen, on the top). Now, if you click one of the results, you get to a detailed page about that.
What i'm trying to achieve is to call the page scroll i mentioned also when you get back to the home, by using "previous page" button or even by clicking home in the navbar. The results list is still there, so i want to scroll it again on the top.
The function i use for the scroll is
const scrollPage = () => {
setTimeout(function () {
const element = document.getElementById("comment");
element.scrollIntoView({
behavior: "smooth",
block: "start",
});
}, 1000); }
and this works when i do the research, since i call it inside the search function. i tried calling the same function with useEffect() but it didn't work, also i tried like
useEffect(() => {
window.addEventListener('load', scrollPage);
return () => {
window.removeEventListener('load', scrollPage);
}}, []);
but it doesn't work. if i click home in the navbar it goes on top of the page and if i use the "previous page" button i get back at the same Y of the list and the beginning of the list doesn't get scrolled.

Route/Redirect to another page in new tab using useNavigate

I am using ag-grid and it has an event onSelectionChanged, which make the row clickable. When I click on row below function is called.
const onSelectionChanged = useCallback(() => {
const selectedRow = gridRef.current.api.getSelectedRows(); //get the row data
let navigate = useNavigate(); //import { useNavigate } from "react-router-dom";
navigate('/Detail', { state: { data: selectedRow[0]} }); //navigate to detail page
}, []);
The function navigates to the detail page and the state is passed. But navigate() calls the Detail page in same tab.
I want to open the page in new tab. Is this possible using this method? or there is another way to accomplish my goal?
react-router isn't supposed to help preserve state when opening things in a new tab. In fact, fundamentally, react isn't supposed to help do this.
I'd approach this in two ways:
If the data is simple enough, pass it as a query or path param using windows.open(window.open("http://link?key="+ value +"&key2="+ value2 ..."); )
Look into other state management methods like localstorage or something else

React Native Navigation Refresh List Screen on back

React Native Navigation Refresh List Screen on back:
this.props.navigation.navigate('Order List', {
order_id: this.state.order_id,
order_status: this.state.od_status,
})
What you want to achive isn't clear, but if want to modify your list of data when going back to your previous screen you could simply use useEffect and modify your list in there.
Note: Your list has to be stored in a local state otherwise the screen wouldn't re-render when updating the list and youl would see no changes on your screen.
better description of the problem would be helpful, but this is general solution for class based components:
componentDidMount() {
this._unsubscribe = this.props.navigation.addListener('focus', () => {
this.loadDataFunction();
}
}
componentWillUnmount() {
this._unsubscribe();
}

How to get background location of modal window from previous page, like Unsplash did?

The background page of modal window in Unsplash is really unique.
Emulation:
click on photo from feed
then click to another photo on modal page to watch effect
refresh page
click to go back on browser
notice the route of background location on modal window
So my question is how to create this background location properly?
Ciao, my personal point of view is that when you go back, Unsplash page re-triggers the modal window you open before. Unspalsh is written in React so, for example, code could be like that:
function Page() {
const [state, setState] = useState({...});
useEffect(() => {
// get data from cache
if (data) {
// (re)open dialog with photo
}
}, [state]); // state in deps so useEffect will be re-triggered each time you enter in Page
}
I don't want to be reductive but this could be a start point.

React with Redux Update only state

I'm working on integrating Redux in an already finished SPA with ReactJS.
On my HomePage I have a list of the 4 newest collections added which on render, I fetch with axios from my database. These are then saved in Redux Store and displayed on the React UI.
My mapStateToProps look something like this:
const mapStateToProps = (state) => ({
credentials: credentials(state),
collections: collections(state)
});
Where credentials is irrelevant and collections is:
const collections = (state) => {
if (state.collectionsHomeViewReducer.fetching === true) {
return {
fetchingCollections: true
}
}
else if (state.collectionsHomeViewReducer.data) {
const response = state.collectionsHomeViewReducer.data;
return {
collections: response.collections,
fetchedCollections: true,
fetchingCollections: false
}
}
else if (state.collectionsHomeViewReducer.fetched === false) {
return {
fetchedCollections: false,
fetchingCollections: false
}
}
};
What is it I want to do:
Update the store state every time another client, or the current client, adds a new collection. Moreover, I do not wish for the UI to update immediately after I dispatch(action), I want it to update when a user refreshes the page or when he navigates to another view and returns ( I believe what I'm trying to say is when componentDidMount is called ).
What have I achieved so far:
By using socket.io, I
socket.emit("updateCollectionsStore")
socket.on("updateCollectionsStore")
and
socket.broadcast.emit("updateCollectionsStore")
in their respective places in the application. The final call of
socket.on("updateCollectionsStore")
after the broadcast, is in the main file of the page, app.jsx where the store is also located. The function there looks like this:
socket.on("updateCollectionsStore", () => {
store.dispatch(getCollectionsHomeView());
});
The store is updated and everything works fine, as viewed from the Redux Dev Tools.
What I can't seem to figure out is to tell the props not to change due to the fact that mapStateToProps is called every time an action is dispatched.
Why do I need this: The HomePage can deal with a continuous UI update and data fetching but I also have a page ReadAllPage where you can real all collections. The problem is if there will always be the newest post on the top, whenever a new one is added, the current one is pushed downwards. In case somebody had the intent to click the one that was pushed down, now he might have accidentally clicked the one that took its place, which is not wanted.
What else should I do different or further to achieve the result I want?
Thank you.
According to your needs, I would have two properties in the state. First is that is currently visible on the HomeView and the second is that is updated via sockets. Once a user navigates to the HomeView you can just replace the first collection with the second one.

Resources