I have a React app(Gatsby) and using #reach/router.
There are multiple pages like user page, follower page...etc.
Fetching data in useEffect hook and here is the problem.
When I navigate to another page from the current page, I'm passing a param, sending it to the next component, for example to a user page, then calling API in useEffect hook in the component with the param. Then you can go to another component like follower page with a param, calling api in useEffect again.
When I try to go back with browser back, the previous data updates again. Ideally I don't want it to get updated every time when I go back to the previous page.
I understand that this happens because I'm calling it in the useEffect hook. Thought about passing data as props with navigate (ex. navigate("/follower", state: { data })), but I think navigate to the page first and fetching data is the best solution for users because when fetching data is taking some time, I want to show skeleton or a loading indicator in the next page. The ideal experience is something like twitter.
Not sure this isn't working because I'm using #reach/router instead of react-router-dom
Any advise is appreciated.
EDIT:
Apologise for my poor explanation.
My problem here is when I keep going back to previous pages like this user page → follower → (another)user → follower ... , browser doesn't remember what were there and useEffect fires everytime. It wasn't happening with react-router before?
My guess is that since I'm using GatsbyJS(SSR) and client-side routing, somehow it generates pages every time even the browser back triggered instead painting it again? I'm not familiar with SSR w/ cliet-routing, hoping to get some info somewhere..
The only way it comes to my mind is using local storage or cookies, within a useEffect with deps ([]), otherwise, each rendering of the page (moving back and forward for example) will trigger again all side-effects available.
Alternatively, you can use useEffect's deps, to only fire the useEffect if the needed dependency has changed.
const SomePage=(props)=>{
const isLoggedIn=props.isLoggedIn || localStorage.getItem('logIn')
useEffect(()=>{
// this will only be fired when yourDeps changes
}, [yourDeps])
return {isLoggedIn ? <div>Hello ${user}</div> : <Link to="/log-in">Log in</Link>
}
You deps (yourDeps) can also check values that you are sending through the location state or from local storate/cookies.
You can also use useRef hook to store "old" values from references but given your generic explanation, I'm not sure which case fits you better.
Related
I am facing a challenge where I was requested to send page_view events (GA4) containing some information that is fetched asynchronously.
The challenge is because since the information is not there yet once the page renders, I can't fire the event until it's there. That's fine.
The problem
Since a page can have multiple components and these components can be fetching some data as well that I need to send, the only way I see to fire this event once the data is available is by relying on the redux store to check for when the data is there. So once it's there, I trigger the page view event.
Something like this:
const subscriptionsData = useAppSelector(
(state) => state?.[REDUX_API.KEY]?.[REDUX_API.SUBSCRIPTIONS]?.successPayload?.data
);
useEffect(() => {
sendPageViewEvent({ subscriptionsData });
}, [subscriptionsData]);
Now if a page has multiple components and other components are also fetching some data that I need to send in this same page_view event, this solution doesn't work anymore.
I did a lot of research but was unable to find a proper way to handle this scenario and I am starting to think the problem is that I am trying to send data that I don't have.
The only solution I can think of to solve this problem is too hacky:
Have a sort of configuration file where we check based on the route,
what kind of fields are expected to be sent to GA, but I am trying
to prevent this because maintainability is bad and likely to
developers to forget to do it.
In general, my main point is: Is it a bad practice to fire asynchronous data inside page_view events?
For click events it should be fine, but for page_view, even if you are doing all data-fetching in one single component in the page and could wait for it to fire the event there, you can't control that you might need in the future to fetch data in another component inside the same page, and then get this same data in the original function... you'd have to fire another event, which would mess up with data in analytics...
I build a project in React using Redux and Router and I have a little question. If I navigate between project pages by clicking buttons, my state from Redux is not deleted.
But if I try to write the url instead of clicking the button to go to the same page, my state is deleted.
How can I resolve this problem?
Your redux store gets deleted because you have refreshed the page and no data related to the main page is present in the redux now ,
If you want to retain data inside redux even when you type url in browser without clicking any button , just use localstorage along with redux , and apply a check if your localstorage is present then store all the data inside redux else store data from redux to local storage .
I hope this solves your issue .
Building a simple E-commerce store with Nuxt and Prismic.
I have this very simple action in my store:
async GET_ALL_CATEGORIES({commit}) {
// gets all the categories from prismic
// Set categories to the state
}
My question is, when I move around the application from / to /category1 to /category1/product1 should I be dispatching this action everytime?
Would one save this array of categories in localStorage?
Should I have an if block in my asyncData that checks for the categories state and if it is empty, dispatch the action, otherwise use whats in state?
How do the pros handle this situation?
Thank you!
It depends on how often you think your 'categories from prismic' would change. If not very often then you can save it to the store and then just read from the store.
Otherwise you may want to query your API etc on every page load, probably in mounted()
EDIT: You many also want to set an expiry date on the state so that it can pull in fresh data at intervals
Overview:
I got this route in my react application
example.com/routeName/:id
This is the entrypoint for my users, they click on the link and see a screen with informations provided by this hash in a right sidebar component.
example.com/routeName/94a31bb9-e6ae-4e9a-8749-0807f9efd0001
Below I attached a kind of wireframe, trying to be more clear about the sidebar:
Wireframe to understand how my app components are shown at the end, and why the hash is important in a visual way
This works fine, I can get the hash and make the request inside my dumb component to display data.
The problem:
I'm doing the fetch to the api in my Layout component, and passing down the data via props to my sidebar that is fixed in my layout, because it is displayed through all the user experience
When my user sign in, my route change, from:
example.com/routeName/94a31bb9-e6ae-4e9a-8749-0807f9efd0001
to:
example.com/nextRouteNameHere
I still see the component with the information I need, but if I refresh the page at the second route, the app crashes, because my sidebar cant find the hash to fetch my api and get the necessary data.
What I've been trying to do:
Persist this route with the hash and make the route change internally - but that doesn't makes sense to me at all, and I could not find any resources even close to this strategy.
Persist this hash in localstorage and get the hash with hooks inside the sidebar. This way if I can't find my hash at the url it'll be in the localstorage and I can fetch my api to get the data. I did it, but doesn't work because the components presents the some behavior, trying to render with no data.
As I'm using redux to manage the global state I've already taken the hash and the fetch response to the localstorage, this way I can take this data through all the aplication, but the hash is what makes my hooks update when I tried to wrote this strategy, and when the user updates the page I got the same behavior, because the hook could not find the :id on the url.
Final question
How can I persist the sidebar with the fetched data I did when I load the page?
NOTE
I did not post the code because at this moment I got too much code trying to solve this and I'm stuck in this problem for almost one month. I'll update this post later on.
I have created a screen that has a flat list with a data source from an external API. I am storing those data in a state, using redux and then retrieving the data to flatlist.
I am for fetching the data from API I am using axios. So, to supply the source of data to flatlist, I am fetching the data in the previous screen. For example - I have a button, by which on pressing that button it will navigate to a new screen which contains a flatlist. So, I am fetching the data by posting axios request by the onPress function of the button from the previous page. And then storing that data to a state in the redux store, and then getting the data as a source to flat list.
I think this is not the right way to do this? How to fetch the data from external API on the same component and how to render that (because within fetching the data, the component will be rendered). How to do this effectively?
As, if everything is correct if the user goes to some other screen and re-enters the screen what will happen? How to do this effectively and optimized?
I think I don't have any code to show. If you guys need any code from above said, do let me know will update them.
You should probably try using componentDidMount for calling your api.
componentDidMount is invoked only once, immediately after the initial rendering occur.
You mentioned you are storing data in your redux store.
You should probably create events like:
const Actions = {
LOAD_POSTS_REQUEST: 'LOAD_POSTS_REQUEST',
LOAD_POSTS_FAILURE: 'LOAD_POSTS_FAILURE',
LOAD_POSTS_SUCCESS: 'LOAD_POSTS_SUCCESS',
};
const postReducer = {
posts: [],
isLoaded: false
};
Now, on LOAD_POSTS_SUCCESS you can set your data which you need in the flatlist with that also set a isLoaded state in the redux store.
Now next time, when user re-enters the screen you can use the state.isLoaded check to call the api.
I am sure that what I am mentioning here is a way simple implementation. Hope this helps.