I'm facing and issue here and I want a second opinion. When the first page of my app is rendered I want to clear my state for security reasons so in my layout class component I write:
componentDidMount() {
this.props.clearState();
}
The problem is that when I'm in the second page of my app and click backslash my state is clearing again. I want somehow to make a condition in my componentDidMount so as not to clear the state if I came from a page of my app. Is this possible? Do you have any other ideas of how to do this? Thanks a lot
If u don't use Redux u can try sessionStorage to store temporarily if the clearState() was fired.
//simple Example
componentDidMount() {
if (sessionStorage.getItem('clearState') === 0) {
this.props.clearState();
sessionStorage.setItem('clearState fired', 1)
}
}
You should try to clear the state of your Component inside componentWillUnmount() lifecycle method. It is the appropriate place to make cleaning.
Related
I am deleting a record from db, for this I am calling an API. When I received an
API response of a successful deletion, I need to re-render all the component again like reload does. I tried it with this.forceUpdate and shouldComponentAgain but no luck.
I also tried with componentDidUpdate, it works but it is calling API infinite times. Below is my code how I used componentDidUpdate:
componentDidUpdate(){
let newThis = this;
getAccounts().then(function(response){
if(response.status===200){
newThis.setState({
Accounts:response.data
})
}
});
}
Please tell me the way to re-render like reload do, but without re-loading the whole page.
When using componentDidUpdate, you should always have a conditional setState which denotes that you need to perform something because the current state or current props is not equal to previous state or props.
componentDidUpdate always gets called whenever your component has updated. In your case what is happening is that you are calling setState without any condition which updates your component, and setState is called again causing an infinite loop in updating the component.
You should have something like this check here:
componentDidUpdate(prevProps, prevState){
let newThis = this;
if(newThis.props.{some-variable} !== prevProps.{some-variable}) {
getAccounts().then(function(response){
if(response.status===200){
newThis.setState({
Accounts:response.data
})
}
});
}
}
Adding conditional setState is very important here else you will end up in an infinite loop.
As per the official docs as well:
You may call setState() immediately in componentDidUpdate() but note
that it must be wrapped in a condition or you’ll cause an infinite
loop. It would also cause an extra re-rendering which, while not
visible to the user, can affect the component performance. If you’re
trying to “mirror” some state to a prop coming from above, consider
using the prop directly instead.
Hope it helps.
If you want to render the component again, then change the props from the parent. If props change then child component automatically going to render. And by this features, you can also render the selective component.
I have a Component say HomePage where I'm calling getCurrentLocation to get the location using GPS. This value will be used to select a value from a Drop Down. User may then use the dropdown to change the value.
When I navigate away from this page and then come back using
const appHistory = createHashHistory();
appHistory.goBack();
the constructor and the componentDidMount are executed again. So the user selected value is lost and i get the default value again.
So where do I put by initialisation code? I come from Ionic where there something like ionViewDidLoad which is executed only when the page loads the first time. Is there an equivalent for this is React.
Below is my code
export class HomePage extends React.Component {
constructor(props){
super(props);
state = {
currentLocationCoordinates:[],
};
this.getCurrentLocation = this.getCurrentLocation.bind(this);
}
getCurrentLocation(){
navigator.geolocation.getCurrentPosition((success)=>{
console.log("Current Location: "+success.coords);
this.setState({
currentLocationCoordinates:[success.coords.latitude,success.coords.longitude],
userLocationCoordinates:[success.coords.latitude,success.coords.longitude]
});
});
}
}
componentDidMount(){
this.getCurrentLocation();
}
}
I would avoid using componentDidMount for this. Make your components as resilient to re-renders and re-mounts as possible.
By the sounds of it you are after an application level state container that will hold your application state regardless of whether your component is mounted or not.
Most of the React community relies on Redux for this although other state containers do exist. I'd suggest having a look at Redux and using it to hold those location details as part of Redux store. They will then be always accessible on your component as props, regardless of whether it re-renders or not.
You need to use ComponentDidMount() together with a flag that detects whether the component has been initialized or not. You are on the right track.
componentDidMount(){
initialized ? "" : this.getCurrentLocation();
}
I have a map of the world and whenever you click on a particular country, it pings and API and gets schools in that country. React then uses leaflet to display all the dots(GEOJSON). After the schools are loaded I have a Dock type thing that will pop up. The problem is that I need to know when the react is done updating. I tried using the react lifecycle methods in the Map.jsx file I have the following code to try to see when the GEOJSON is done rendering:
componentWillUpdate() {
console.log('CWU');
}
componentDidUpdate() {
console.log('CDU');
}
But in the console I get the following printouts:
CWU, CDU, CWU, CDU, CWU, CDU
So both functions run 3 times, for another country both functions run twice. So I cant put the function that brings up the Dock in either componentWillUpdate or componentDidUpdate because I would need to run the function after the 3rd 'CDU' or for the other country after the second 'CDU'. Is there anyway way to know when react has finished rendering ?
I found a way to solve it. I'll try my best to explain it:
I have a state variable called
didUpdate = false
The API changes a particular entry in the props
so in componentWillUpdate I check to see if the next state is different than my current one if so I set didUpdate to false. This makes it so that it doesn't display.
Then in my componentDidUpdate I check to see if previous state is different than my current one if so I then set didUpdate to true. This then makes it so the dock is shown.
Here is some code:
componentWillUpdate(nextProps, nextState) {
if (nextProps.X !== this.props.X) {
this.setState({
didUpdate: false,
})
}
}
componentDidUpdate(prevProps, prevState) {
if (prevProps.X !==this.props.X) {
this.setState({
didUpdate: true
})
}
}
You can use
componentWillUnmount()
componentWillUnmount() is invoked immediately before a component is unmounted and destroyed. Perform any necessary cleanup in this method, such as invalidating timers, canceling network requests, or cleaning up any subscriptions that were created in componentDidMount().
I'm running on Android and if I used the hardware back button to exit the application the componentWillUnmount function gets called. However, if I use the square button to show the list of running apps and swipe to close the function does not get called.
Any ideas on how to detect when the app is being closed so that I can clear timers, save data etc.
Thanks.
You can check AppState Api for information about detecting current state foreground or active. https://facebook.github.io/react-native/docs/appstate.html
I ran into the same problem. To solve it, I didn't attach an event listener to the stateChange. Instead I just look at AppState.currentState inside of the componentDidMount() function.
The problem was that eventListeners were getting attached when the component mounted, but not becoming detached at componentWillUnmount.
If you are using react-navigation 4.x you can use the code below (Copied from somewhere else).
I think this issue will be solved in react-navigation 5.x.
componentDidMount() {
const {navigation} = this.props;
this.focusListener = navigation.addListener('didFocus', () => {
const focused = navigation.isFocused();
if (focused) {
console.log('mount');
}
});
this.blurListener = navigation.addListener('willBlur', () => {
console.log('unmount');
});
}
componentWillUnmount() {
this.focusListener.remove();
this.blurListener.remove();
}
you can set condition for costume function that u write for hardware button , for example when ( for example for React Native Router Flux ) Actions.currentScene === 'Home' do something or other conditions u want .
Even though there are many questions with the same subject line, I could not get an answer for my problem.
Problem
I have a select dropdown. On click of which, I call an Api which fetches some key values. I consider this set of key value input fields as a component. So each and every time onChange of my select drop-down, I have used lifecycle methods to handle API Calls. Also, I record these input key values and send back their state to parent component.
According to ReactJS lifecycle methods:
I use
componentDidMount
To call the API for the first time after initial render. This works.
componentDidUpdate
To call the API for subsequent API calls on select drop-down change. But here is the problem. When I try to update the state of input fields the program falls into an infinite loop and hence there are infinite API calls. I am pretty sure after debugging that the problem is with setState(), But I couldnt find the best way to handle states in componentDidUpdate method.
This link exactly replicates my problem but i want a standardized solution
Hope this is clear.
Thanks for the help in advance!
This is spelled out pretty clearly in the docs:
componentDidUpdate(prevProps) {
// Typical usage (don't forget to compare props):
if (this.props.userID !== prevProps.userID) {
this.fetchData(this.props.userID);
}
}
You may call setState() immediately in componentDidUpdate() but note
that it must be wrapped in a condition like in the example above, or
you’ll cause an infinite loop.
You can use setState() within componentDidUpdate(). But you have to use the condition for that. Otherwise, it get infinite loop.
As the example,
componentDidUpdate(){
if(this.props.id !== this.state.id) {
this.setState({
id: this.props.id
});
}
}
This happens because setState triggers a call to componentDidUpdate.
When componentDidUpdate is called, setState does not check whether or not state change has occurred. It simply calls componentDidUpdate again and again, which leads to stackoverflow.
class Component extends React.Component{
constructor(props){
super(props);
this.state = {changeState: false}
}
componentDidMount(){
this.setState({changeState: true});
}
componentDidUpdate(){
this.setState({changeState: false});
}
}
Here, first changeState is set to false in constructor, and then componentDidMount is triggered, which sets state of changeState to true. This state change triggers componentDidUpdate, which sets the state of changeState again to true. This triggers componentDidUpdate again and again.
You have to check the real difference between two state objects.
Below you can find my solution, My state object has movies, which is an array of objects. I edited and movie and then comparing these two arrays.
async componentDidUpdate(prevProps, prevState) {
if (prevState.movies.filter (e => this.state.movies.includes(e))) {
const response = await axios.get("http://localhost:3002/movies");
this.setState({ movies: response.data })
}
}
Yes you cannot setState() inside componentDidUpdate it would lead to infinite loop.Instead you can call a function onChange event and change the state there.