componentDidMount() on reloading component - reactjs

I have components A and B, both of which have their own componentDidMount() methods. Think of them as two separate modules that are NOT loaded together. It's either A or B but not together.
My simple question is this:
If I hit component A, then B, then back to A, will componentDidMount() in component A be called on the second one?
When I read the documentation, it states that componentDidMount() is called only once and componentDidUpdate() is called in all component updates but I'm not 100% clear if this is happening in the entire life cycle of my app.
I'm trying to figure out the logic for API calls. I may or may not need to make an API call for component A again so I have some logic that handles that. Just trying to make my logic work for making that call.
So, the question simply is, will I hit componentDidMount() in component A on subsequent loads during a user's session? A user session may last a long time during which the user may come back to both component A and B many a times.

The answer is yes, every time you switch components you call again for componentDidMount().
More about that here - https://reactjs.org/docs/react-component.html
The logic for API calls in React itself is most like:
Create container which call for API in componentDidMount method.
Create external dumb components which are imported to the container, call them in the render() method and pass the data via props
Create logic which is executing which component should you call now( react-router-dom library is also good approach for conditional rendering)
I hope I explained you that a bit. feel free to ask some questions!

Related

Api call in render method of reactjs

I have a code in which an API call is made inside the render method in a react app, is it correct?
The API call is made from a function placed inside a const function which is placed in another file
render method is place for presenting various elements to user and these elements can be used to trigger an api-call for various purposes. For example - checking validity of text entered in input-element, sending form-data async-ly to server, etc.
And this is a nice practice to put the code into various modules or separate files for better management, etc. for ex. call is wrapped inside a function and placed in a different file. Webpack helps in filling all various modules in place.
So it is alright to put api calls in render and calling a function defined inside another file for the same.
It is not correct.
1) If the api call is waiting for the call to complete(await or promise resolve), Then it is essentially blocking render.
2) React might call render function many times[it may or not lead to DOM update], which means you will be making redundant api calls as many times.
It is ok to do so, if it is in response to an event.
So No, just put the api call in componentDidMount or ComponentDidUpdate or if you are using hook, add a useEffect.
Good Luck!
It really depends on the use case.
There is nothing wrong with doing so as long as you aren't calling it everytime it re-renders. I assume you are making the request upon triggering of certain events(such as onClick). If yes, it may be cleaner to encapsulate it within a method.
async doSomething = () => {
// do the rest
// make API request
await getRequest();
}
return <>
<button onClick={() => this.doSomething()}/>
</>;
If the request is to be made only once and when the component is initialised, you should make that request within the componentDidMount lifecycle hook. According to the documentation for componentDidMount,
componentDidMount() is invoked immediately after a component is
mounted (inserted into the tree). Initialization that requires DOM
nodes should go here. If you need to load data from a remote endpoint,
this is a good place to instantiate the network request.
Otherwise, calling it on render() will result in the API request to be triggered everytime there is a re-render.

Correct way to fetch data with server side rendering (Next.js, when to use componentDidMount and when to use componentWillMount)

I am using Next.js, in the _app.js page (where we set a general webapp state) I have 2 types of data that I need to have in the header (so for every component).
1) The first type is the header info, this info should be rendered before the app loads. I will use get getInitialProps to call the endpoints and put them into the props and then to componentWillMount to add them to the state.
2) The second type is the data for the Search component, it as a lot of data and I don't particularly mind loading it while the app is already rendered as It is not displayed in the first user visual.
So I am gussing that here it is much better prefered to use componentDidMount and asynchorslly call the endpoint that fetches the serach object data and than adding setting the state with it.
The purpose of this questionis double:
1) Review - Am I thinking about this correctly or did I miss something?
2) Question - now, when the data is loaded after first render, I am passing the data like so: _app.js -> Layout -> Menu -> SearchBar
so my question is, in my searchBar I need to do something like
componentDidMount() {
this.setState({ options: this.props.searchBarSource })
}
But, because _app.js is filling this data with an async call, wouldn't this mean that I will always get an empty object?
WWhat is the correct way to solve this? If I setTimeOut to around 3 seconds and then set the data is it a normal solution or very hacky and there are better ways?
What your are trying to do makes sense. Coming to NextJS, you need to be very deliberate about which data should load server side and which shouldn't.
Here are some pointers:
There is no need to setState in the search component, you can
use this.props.searchBarSource as Kunukn mentioned.
[Note - If you are combining getInitialProps and client side (shallow routing), when the user navigates to a new client side route, the initialProps will be undefined. A workaround might be to store initialProps in state or Local Storage.]
The point of getInitialProps is to load async data before the
component mounts. You will always receive the resolved Promise on
componentDidMount, so your this.props.searchBarSource will never
be empty (or more correctly, pending).

Do I have to initialize the component state in both constructor() and componentWillReceiveProps()?

In my React/Redux application, I trigger an API call in the index.js (The entry point) as I want the data to be available even before user navigates to the component.
Actually, this approach helps to reduce the user's wait time as we'll have the data loaded before user reaches the component.
In our use-case, we need to initialize the component state with the props (props are passed from store). I faced below issue in the approach.
case 1: Let's assume user has reached the component before the API
returned that data. In this case, that particular store object will be
empty and the props (which is passed from react-redux connect
wrapper) will be undefined/null. So I need to render "Loading.."
message. When the data arrives, we initialize the component state
using setState() in componentWillRecieveProps().
case 2: If data has arrived before user navigates to the component.
For this case, We can either use constructor() or componentWillMount() to initialize the state from props, as props is having the data. I can't rely only on componentWillRecieveProps() as, it'll not execute during the initialization life cycle.
So I ended up doing the same initialization steps in 2 places as component should handle both cases. Is this a right approach? or Is there any better approach to avoid these kind of DRY code.
Thanks in Advance!!!
I've had the same exact issue that you outlined and also wanted a DRY solution, so I ended up creating a HOC (higher order component) for this purpose:
https://www.npmjs.com/package/react-prepare-wrapper
It lets you assign a single function to be called for both componentWillMount and componentWillReceiveProps.

How to reset state of a child reactjs component

I have a react.js app which loads data from an API displays a bunch of questions (textboxes, radiolist, checkboxes, etc). The user fills them in and submits all answers back to the API, which then send a new set of questions.
All these questions are in a single object, so I've created parent react.js component which holds the current set of questions in state. When the state changes it re-renders each question below. This works pretty much fine.
The problem is that sometimes the API displays the exact same question for twice in a row, but as this is held in state and react.js is clever enough to know it doesn't need to render a completely new component, because the old one will do (with a few small updates).
The problem is that if I select a radio button on the first one, based on the initial data stored in state of the child component, which was initially set within componentDidMount). But when the second question comes along, because its essentially the same component, the state remains. The constructor is not called again.
I think I should be using one of the other events, perhaps:
componentWillReceiveProps
componentWillMount
componentWillUpdate
but I can't figure out which one is the most consistent one.
I basically want to reset the selectedAnswer everytime the parent has received new data from the API and essentially re-render all child components (but react won't do that).
Edit
I wonder instead of trying to reset this via the internal lifecycle events, whether I can pass in a different set of props into the component, so it can decide whether to re-create or re-render in the usual way.
okay so to optimally do this lets suppose you api which returns the set of questions, it might contain some id associated with it. Using that id create a uniq key for every child component while rendering something like below
<Child key={`${data_id}_${index}`} />
This will ensure that for the same set they do not keep mounting again and again and will only mount if a new data set is fetched in which case data_id will change which would cause remounting of each and every child component
I'd encourage you to check out Redux. It makes managing state much easier. I'd contribute some code on here but I am not sure I actually understand the question. If you linked us to your Github, then I could probably answer this specific question.
Also, it seems like you don't really need to touch state. It sounds more life attaching an event and controlling state that way. For example, using onSubmit, you can make an API call (and whatever else) and then have another function to reset the form state afterwards. It would be pretty straight forward, especially if you are using then/catch Promises.

Call action after callback from listener and... cannot dispatch in the middle of dispatch?

I'm in trouble with React and Flux... We have an application that is pretty similar to the new Flux chat example. We have the famous error "cannot dispatch in the middle of dispatch". But, it's hard to us to think in a good way to resolve this problem in some cases.
Our doubt is identical to this: https://groups.google.com/forum/#!topic/reactjs/mVbO3H1rICw, but I can't understand very well the solution adopted. As far as I understand, is not a very elegant solution.
Here is the sequence of events:
Action A is dispatched;
The Store updates it's internal state and emits the change message;
A react component X receives the change message (by the callback of the listener) and updates it's state (setState);
The component X renders and as part of that a new component Y is mounted too. We choose the component (Y, Z, etc...) to be rendered using the information of the state;
The new component Y needs data to display that isn't initially loaded. So we call a API in the componentDidMount() of the component Y, that calls an action B.
Then, with the new dispatcher in the Action B, we have this dispatch error.
If you consider that our application logic have some issue, I can bring some practicals examples to show why this scenario is common for us. Any idea of how refactor this "flux" is very welcome.
Thanks for any help!
i think you need to use the waitFor token from the dispatcher before launching action b (youre using the dispatcher from the flux npm module right?). additionally, what can you do is make the ajax call from your store during action A if youre always going to need that data from action b.
solution b would look like this in /* store.js */
Dispatcher.register(function(payload){
switch payload.type {
case ACTION_A:
/* do your state logic */
StoreDataAccessLayer.apiCall()
}
}
where you have a Data Access Layer class / object that wraps your ajax call to the api. using the state from your store as inputs, and calling trigger change from the success function. this is the primitive solution i've seen when using the flux npm module if youre not going with waitFor

Resources