I have a component that makes an API request, gets some data. Then the data is put into a child component that puts it into redux:
Pseudocode:
let data = await apiRequestHere(); //some graphql query, using graphql-request
return (
<div>
<MyReduxComponent data={data} /> //inside here, data is processed and put into redux state
</div>
);
While the API request runs, I am showing a spinner.
Redux-Persist
Just implemented redux-persist. However, the way everything is set up right now is that the API request is made in any case, and the spinner is shown every time, so even with redux-persist it will wait for the data to come back from the server, making using redux-persist pointless.
How I would implement redux-persist properly and make sure that if there is data in redux-persist, use that data, make an API request in the background, and if there are any changes, then update. Don't want to block my whole app every time.
Did I go wrong in my setup here?
Related
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.
For example, let's take a simple web application with comments feature. In my understanding, when a user posts a new comment, the following would occur:
display UI loader;
update the front-end state;
send a fetch request to the API to post a new comment;
Wait for the response;
send another fetch request to the API to request the new list of comments;
waiting;
update the front-end state with new comments;
update UI to reflect the new state with a new comment;
And the user needs to wait while front-end app interacts with back-end on almost every data change. The same way we did it earlier with PHP/Python/Ruby, ajax, server-side rendering and templates.
That makes me think what's the point of adding so much front-end complexity with something like react, when the result is basically the same.
My question is: are there any alternative approaches to this? Is it possible instead to do the above case the following way:
user clicks to post a comment;
update the front-end state;
update UI to reflect the new state with a new comment;
sync front-end state with API DB in the background;
Well, as your question is tagged react, you could use the Apollo library (it is intended to work together with graphql on the backend) for data fetching. It offers a feature called Optimistic UI, which will be update the frontend with the respected result, until it receives an answer from the backend. If the expected result differs from the received one, the component will change the UI automatically to the real result. In case of an error, it will show an error message.
You definitely could, your first method is just way of doing it.
Apart from 'syncing' your front-end state, another method is also to just pre-emptively update the UI (step 7 & 8 in your first method) before doing step 3-6, and only reverse the action if the API call failed. This should allow for slightly better UX for the end-user too.
I get it that you think it's waste of time for users to wait until requests are successful. However, isn't it more important to stop users from keeping making bad requests to the server?
So, what I would do is just to stop fetching data from the database every after users make requests.
Fetching the DB data to begin with and store them in redux states
Make requests to the DB while holding users from doing anything
Make changes to the redux state if the requests are successful
But what you want to do could be done like this
Fetching the DB data to begin with and store them in redux states
Make changes to the redux state while making requests to the DB in the background
Depending on whether the requests fail or not, roll back the change users made from the redux state
I was curious to know if making an API request outside of the lifecycle/useEffect is a valid way to make the call?
https://stackblitz.com/edit/react-useeffect-button has two functional components, the parent component makes an API call and passes the data to the child component, initially specified the limit of data to be fetched from the endpoint as 2 and the parent component has a LoadMore function that is passed as a prop along with the data to the child component.
Using the react-slick slider to display the images in the child component and the Load button onClick will call the function LoadMore inside the parent component and then it makes an API call and appends the new data from API to the old Data. The load button will append one Image to the existing images.
is this a good way to make API requests or should it be done only in the lifecycle methods?
is this a good way to make API requests outside useEffect/lifecycle.?
It depends on your requirements.
should it be done only in the lifecycle methods?
It depends on your requirements.
There's nothing wrong making API request outside useEffect. But it should be done in some other function or it will cause the request to go on every re-render.
And if the response if being saved in a state variable.
Then it will go into the infinite loop.
When do we make the request in useEffect and when by some other function?
Requests that fetch data or send some info at the time of initialization of the component is supposed to be made in componentDidMount/useEffect
And requests that are supposed to be sent on some action (like in your case, onClick) so they are hit according to that event.
There's neither good or bad, it's all about your requirements.
If you are making an API call to get data from initial render then using a lifecycle hook is a good approach. In your scenario, you want to make an API request when hitting a button. In that case it can be a simple function without any lifecycle hook method.
The only key part here is that you are maintaining the state and rendering the view from the state.
This depends on your needs.
if you think whenever your params change,API call will be triggered.
in this case, you should set the API call inside the useEffect.
If you want your API call triggered on page load(ComponentDidMount). In this case, you should set API call inside the useEffect
Otherwise no need to set api call inside useEffect.
In your case no need to set API call inside useEffect. because you hit the API call when the user clicks the button. So no need to use useEffect.
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.
in react I want to send a sync instead of async ajax request to the server for getting category list on constructor because if the server is busy, the response will be late that means the page will be rendered without category list.
I think it is a good idea that creates/edit a JSON file after every category event but I want to learn the right way.
how can I do it or what is the right way to it?
I would set an empty array in the state in the constructor. And in componentDidMount I would start an async request. When it returns it updates the state and you get your category list.
You can set a loading state as well. Set true at the start of ajax request and set false as you get back the result.
Use the loading state with conditional rendering to display a loading indicator.