Can I call APIs in componentWillMount in React? - javascript

I'm working on react for last 1 year. The convention which we follow is make an API call in componentDidMount, fetch the data and setState after the data has come. This will ensure that the component has mounted and setting state will cause a re-render the component but I want to know why we can't setState in componentWillMount or constructor
The official documentation says that :
componentWillMount() is invoked immediately before mounting occurs. It
is called before render(), therefore setting state in this method will
not trigger a re-rendering. Avoid introducing any side-effects or
subscriptions in this method.
it says setting state in this method will not trigger a re-rendering, which I don't want while making an API call. If I'm able to get the data and able to set in the state (assuming API calls are really fast) in componentWillMount or in constructor and data is present in the first render, why would I want a re-render at all?
and if the API call is slow, then setState will be async and componentWillMount has already returned then I'll be able to setState and a re-render should occur.
As a whole, I'm pretty much confused why we shouldn't make API calls in constructor or componentWillMount. Can somebody really help me understand how react works in such case?

1. componentWillMount and re-rendering
Compare this two componentWillMount methods.
One causes additional re-render, one does not
componentWillMount () {
// This will not cause additional re-render
this.setState({ name: 'Andrej '});
}
componentWillMount () {
fetch('http://whatever/profile').then(() => {
// This in the other hand will cause additional rerender,
// since fetch is async and state is set after request completes.
this.setState({ name: 'Andrej '});
})
}
.
.
.
2. Where to invoke API calls?
componentWillMount () {
// Is triggered on server and on client as well.
// Server won't wait for completion though, nor will be able to trigger re-render
// for client.
fetch('...')
}
componentDidMount () {
// Is triggered on client, but never on server.
// This is a good place to invoke API calls.
fetch('...')
}
If you are rendering on server and your component does need data for rendering, you should fetch (and wait for completion) outside of component and pass data thru props and render component to string afterwards.

ComponentWillMount
Now that the props and state are set, we finally enter the realm of Life Cycle methods
That means React expects state to be available as render function will be called next and code can break if any mentioned state variable is missing which may occur in case of ajax.
Constructor
This is the place where you define.
So Calling an ajax will not update the values of any state as ajax is async and constructor will not wait for response. Ideally, you should use constructor to set default/initial values.
Ideally these functions should be pure function, only depending on parameters. Bringing ajax brings side effect to function.
Yes, functions depend on state and using this.setState can bring you such issues (You have set value in state but value is missing in state in next called function).
This makes code fragile. If your API is really fast, you can pass this value as an argument and in your component, check if this arg is available. If yes, initialise you state with it. If not, set it to default. Also, in success function of ajax, you can check for ref of this component. If it exist, component is rendered and you can call its state using setState or any setter(preferred) function.
Also remember, when you say API calls are really fast, your server and processing may be at optimum speed, but you can never be sure with network.

If you need just data only at first run and if you are ok with that. You can setState synchronously via calling a callback.
for eg:
componentWillMount(){
this.setState({
sessionId: sessionId,
}, () => {
if (this.state.hasMoreItems = true) {
this.loadItems() // do what you like here synchronously
}
});
}

Related

Call componentDidMount when API responds

In my project I have a call to an action that makes a webservice call and in turn dispatch actions to the result of the ws, these actions edit the store.
My problem is in :
ComponentDidUpdate () {
If (this.props.messages.length) {
Const items = this.props.messages.filter (this.isDisplayable);
This.timer = setInterval (() => {
If (items.length> 0) {
This.props.popItem (items);
} Else {
ClearInterval (this.timer);
}
}, This.props.interval);
}
}
In fact it is launched several times and I have warnings of
Warning: flattenChildren (...): Encountered two children with the same
key, 1. Child keys must be unique; When two children share a key,
only the first child will be used.
I used the componentDidMount but it launches it before api responds.
my question is:
Is that there is a way to update the component only at the response of my action, or alternatively to pass the warnings ?
try this :
componentWillReceiveProps(nextProps) {
if (this.props.messages === nextProps.messages) return;
i had some probleme and i resolve it by force update
forceUpdate () {
If (this.props.messages.length) {
...
}
}
In my project I have a call to an action that makes a webservice call and in turn dispatch actions to the result of the ws, these actions edit the store.
None of the methods componentDidMount and componentDidUpdate are good.
Observe the Store in Redux and update your component accordingly when the correct action TYPE is found.
Since you are using the Redux architecture, the state for all your components is in a single place — in the Store.
yes i know, but the problem is that componentDidUpdate is called several times which gives me the index error.
This is quite normal in React. Check this lifecycle.
What you should do is the govern the Redux architecture.
I will try today to provide some diagrams for you.
In general, anything you do will be from the global Store.
You may forget the React.Component state, and props you had in the non-Redux applications.
You typically need to use the Wrapper as a context provider around your app, where the context is the property of React.Component.
The context will be passed to all children and grandchildren so this will be the global Store organization.
Then you will need to read the Store from the context, and call the two typical methods: dispatch and subscribe.

react-redux store not updating within onClick function

I'm experiencing this weird issue where my react-redux store is updating, but is not updating within the function that calls the actions.
this.props.active is undefined, then I set it to an integer with this.props.actions.activeSet(activeProc), but it remains undefined and enters the next if condition.
I know my app is working because everything else works with this.props.active having the correct value.
Is this supposed to happen?
edit:
After doing some testing, it appears that the state remains the same inside the onClick function.
All calls to console.log(this.props) made within the onClick function show no change to the state, but adding setTimeout(() => {console.log(this.props)}, 1) at the end to test shows that the state is being updated.
Other parts of the app are working as intended, with state changes applied immediately.
But I still don't understand what is going on.
Component function code
() => {
console.log(this.props.active); // undefined
if (this.props.active === undefined && this.props.readyQueue.length > 0) {
let activeProc = this.props.readyQueue[0];
this.props.actions.readyPop();
this.props.actions.activeSet(activeProc); // set to an integer
this.props.actions.execStateSet("Running");
}
console.log(this.props.active); // still remains undefined
if (this.props.active === undefined) {
this.props.actions.execStateSet("Idle");
}
}
function mapStateToProps(state, props) {
return {
active: state.ProcessReducer.active,
};
}
Action code
export const activeSet = (procId) => {
return {
type: 'ACTIVE_SET',
procId
}
}
Reducer code
case 'ACTIVE_SET':
return Object.assign({}, state, {
active: action.procId
});
Your Redux state updates synchronously with the dispatch of your action. Your reducer has executed by the time the dispatch call returns.
However, React isn't Redux. Redux tells React-Redux's wrapper component that the state has changed. This also happens before dispatch returns.
React-Redux then tells React that the component needs to be rerendered by calling forceUpdate. React then waits until it feels it's a good time to take care of that. I haven't looked, but it probably uses setImmediate or equivalent but it's async. This allows React to batch updates and maybe there are other reasons.
In any case, the React-Redux wrapper component will get rendered by React when the time comes and it'll use your mapStateToProps to distill theprops out of the state and then passes them to React as props for your actual component. Then, when React feels it's an okay time, it calls your render method or function. It may do all kinds of things in before that, such as calling componentWillReceiveProps or rendering some other component that also needs rendering. In any case it's none of our business. React does its thing. But when your Render function is called, your props will now reflect the new state.
You shouldn't rely on new state in an onClick handler. The onClick should only call the bound action creator, which I guess is now more aptly called an action dispatcher. If something needs to be done with the new state, you should use Redux-Thunk middleware and create a thunked action creator. These have access to getState and if they don't perform any internal async stuff, then the entire action can actually be just as synchronous as a simple dispatch (not that you'd need that in a simple onClick handler).
Finally, React is very asynchronous in nature. Think of it as telling React what you want (component + props) and letting React take it from there. If React needs to know how to turn a component into DOM elements, it'll call your component's render function. How or when React does is thing is an implementation detail that doesn't concern us.

What are typical use cases for React lifecycle methods like componentWillReceiveProps

componentWillReceiveProps and other lifecycle methods seems like deceptive temptation to bring unnecessary complexity and noise to the code in the hands of inexperienced React coder. Why do they exist? What are their most typical use cases? In the moment of uncertainty, how would I know if the answer lies in the lifecycle methods?
I have been using react for couple of months now, and most of my work is creating a large application from scratch. So the same questions have presented themselves in the start.
The following information is based on learning while development and going through multiple docs out there to get it right.
As asked in the question here are couple of uses cases for the lifecycle methods in react
componentWillMount()
This is called once on the server side, if server side rendering is present, and once the client side.
I personally have used it just to do api calls which do not have direct effect on the components, for example getting oAuth tokens
componentDidMount()
This function is mostly used for calling API's (here is why to call it in componentDidMount and not in componentWillMount)
Components state initialisations which are based on the props passed by parents.
componentWillReceiveProps(nextProps,nextState)
This function is called every time props are received except the first render
Most common use I have encountered is to update the state of my current component which i can not do it in componentWillUpdate.
shouldComponentUpdate(nextProps, nextState)
This method is invoked before the render happens when new props or states are received. Here we can return false if the re-render is not required.
I see this as a performance optimisation tool. In case of frequent re-rendering of parent component this method should be used to avoid unnecessary update to current component
componentWillUpdate(nextProps,nextState)
this function is called every time a component is updated, it is not called when component mounts
Carry out any data processing here. For example, when a api fetch returns data, modelling the raw data into props to be passed to children
this.setState() is not allowed in this function , it is to be done in componentWillReceiveProps or componentDidUpdate
componentDidUpdate(prevProps,prevState)
Invoked right after the changes are pushed to the DOM
I have used it whenever the required data is not at the first render (waiting for api call to come through) and DOM requires to be changed based on the data received
Example, based on the age received show the user if he is eligible for application for an event
componentWillUnmount()
As the official docs mentions, any event listeners or timers used in the component to be cleaned here
In the moment of uncertainty, how would I know if the answer lies in
the lifecycle methods?
What analogy i suggest
Change is triggered in the component itself
Example, Enable editing of fields on click of an edit button
A function in the same component changes the state no involvement of lifecycle functions
Change is triggered outside of the component
Example, api call finished , need to display the received data
Lifecycle methods for the win.
Here are some more scenarios -
Does the change in state/props requires the DOM to be modified?
Example, if the current email is already present , give the input class an error class.
componentDidUpdate
Does the change in state/props requires to data to be updated?
Example, parent container which formats data received after api call and passes the formatted data to children.
componentWillUpdate
Props being passed to a child are changed , child needs to update
Example,
shouldComponentUpdate
Adding an event listener
Example, add a listener to monitor the DOM, based on window size.
componentDidMount
'componentWillMount' , to destroy the listner
Call api
'componentDidMount'
Sources -
Docs - https://facebook.github.io/react/docs/component-specs.html
this scotch.io article which cleared the lifecycle concepts
Event Listener - https://facebook.github.io/react/tips/dom-event-listeners.html
Some typical use cases for the most commonly used lifecycle methods:
componentWillMount: Invoked before initial rendering. Useful for making AJAX calls. For instance, if you need to grab the user information to populate the view, this is a good place to do it. If you do have an AJAX call, it would be good to render an indeterminate loading bar until the AJAX call finishes. I've also used componentWillMount to call setInterval and to disable Chrome's drag and drop functionality before the page renders.
componentDidMount: Invoked immediately after the component renders. Useful if you need to have access to a DOM element. For instance I've used it to disable copy and pasting into a password input field. Great for debugging if you need want to know the state of the component.
componentWillReceiveProps: Invoked when component receives new props. Useful for setting the state with the new props without re-rendering.
componentWillReceiveProps is part of Update lifce cycle methods and is called before rendering begins. The most obvious example is when new props are passed to a Component. For example, we have a Form Component and a Person Component. The Form Component has a single that allows the user to change the name by typing into the input. The input is bound to the onChange event and sets the state on the Form. The state value is then passed to the Person component as a prop.
import React from 'react';
import Person from './Person';
export default class Form extends React.Component {
constructor(props) {
super(props);
this.state = { name: '' } ;
this.handleChange = this.handleChange.bind(this);
}
handleChange(event) {
this.setState({ name: event.currentTarget.value });
}
render() {
return (
<div>
<input type="text" onChange={ this.handleChange } />
<Person name={ this.state.name } />
</div>
);
}
}
Any time the user types into the this begins an Update for the Person component. The first method called on the Component is componentWillReceiveProps(nextProps) passing in the new prop value. This allows us to compare the incoming props against our current props and make logical decisions based on the value. We can get our current props by calling this.props and the new value is the nextProps argument passed to the method.

ReactJS - waiting for action to finish within componentDidMount

Code in question is below. I have an async UserActions call within componentDidMount, and immediately afterwards I am looking to user information from within the UserStore populated by this action. Clearly, I cannot rely upon UserStore.isLargeAccess() being defined. Is the best convention to place the code relying on the action within a callback, or am I missing some bigger design choice?
componentDidMount() {
this.changeListener = this._onChange.bind(this);
UserStore.addChangeListener(this.changeListener);
OrganizationStore.addChangeListener(this.changeListener);
// Fetch user info
UserActions.get(AuthStore.username);
// UserStore.isLargeAccess() is undefined here,
// because the previous action has not finished.
if (UserStore.isLargeAccess()) {
OrganizationActions.getUsers(this.state.organization);
}
if (UserStore.isGlobalAccess()) {
OrganizationActions.getOrganizations();
}
}
How it should to work (If I understand your flow):
You should register different callbacks for each of your stores (otherwise you don't know which store emit event)
You start some async work.
When async work is finished then it dispatch action with some data from async work
your stores UserStore and OrganizationStore listens for this action, and when they receive it, they do some job and emit change.
When they emit change, then they call callbacks from your component. In each callback you know which store invoke it, And therefore you know from what store get data.

How do I update the state (using ReactJS) if I should not call setState in componentWillUpdate?

When I setState in componentWillUpdate, componentWillUpdate runs in an infinite loop that doesn't stop getting triggered.
This never gives my render a chance to reflect my changes. How can I change the state if I shouldn't use componentWillUpdate?
Edit: I already have some understanding that setState should not be called in componentWillUpdate. I'm just confused what I should do as an alternative.
Edit #2: I started with componentWillReceiveProps but I can't seem to trigger this function when my Parent component changes state. I provide that state from the parent as a props to my child.
First thing to do is to check official documentation for this method (link). Where you can read when the function is actually called.
Then read common mistake(note):
You cannot use this.setState() in this method. If you need to update state in response to a prop change, use componentWillReceiveProps instead.
You change the state and React automatically calls componentWillUpdate.
I understand this is cautioned against in the guide but I am not sure I can see the problem with calling setState from within componentWillUpdate. True, it may result in infinite recursion unless of course you provide a bottom to that recursion (a way to break out of it). E.g. a way could be to check the second (nextState) parameter in componentWillUpdate and not invoke setState again if some condition is met (which is when the recursion ends).
As a minimal example, imagine a component that has no properties at all, only two pieces of state. Further imagine that the second piece of state is asynchronously obtained from the first. E.g. the first piece of state could be some parameter to provide to an Ajax call, and the second piece of state is the result of that call. So basically you call this.setState to configure the parameters and then inside componentWillUpdate you can do something like the following (to keep things simple I use a window.setTimeout as a placeholder for an Ajax call):
const ComponentWithAsyncState = React.createClass({
getInitialState: function() {
return {
ajaxParams: '',
ajaxResult: ''
};
},
setAjaxParams: function(params) {
this.setState({ajaxParams: params});
},
componentWillUpdate: function(_, nextState) {
if (nextState.ajaxParams!=this.state.ajaxParams)
window.setTimeout(function imagineThisIsAjax() {
this.setState({ajaxResult: `result from ${nextState.ajaxParams}`});
}.bind(this), 2000);
},
When, (e.g. through some controls managed by this component) the ajaxParams change, the sequence of actions will be something like (where ~~> denotes asynchronicity):
setAjaxParams --> this.setState --> componentWillUpdate ~~> imagineThisIsAjax --> this.setState --> componentWillUpdate
I.e. the second call to componentWillUpdate will not result in a further this.setState and thus the recursion will end there.

Categories

Resources