'Trying to run function only if state changes
I want to run the set totals function only if the hour's state has changed. It is running every time the component mounts instead of only if the value changes. The this.state is apart of a context file that is extremely large so I only pasted the function being used
context.js (Class Component)
set Total
if (this.state.hours > 0) {
this.setState((prevState) => {
if (prevState.hours !== this.state.hours) {
console.log(prevState.hours);
}
return {
total: this.state.total + this.state.hours * ratePerHour * Math.PI,
};
});
console.log(this.state.total, '+', this.state.hours, '*', ratePerHour);
}
This is my component tha
import React, { useState, useEffect, useContext,useRef } from 'react';
import { ProductContext } from '../pages/oniContext';
import { Container,Badge } from 'reactstrap';
import {
Subtitle,
Description,
Titlespan2,
} from '../components/common/title/index';
import { total } from '../components/total';
export const FinalQuote = () => {
const pCR = useContext(ProductContext);
const prevCountRef = useRef();
useEffect(() => {
alert('Run')
console.log(pCR.hours, 'Final Quote Run', pCR.total);
pCR.setTotal();
console.error(pCR.hours);
}, [pCR.hours]);
return (
<section className="testimonial-wrapper gradient-color" id="testimonial">
<Container>
<div className="main-title-wrapper">
<Subtitle Class="site-subtitle gradient-color" Name="Your Quote" />
<Titlespan2
Class="sitemain-subtitle"
Name={`$${Math.round(pCR.total)}`}
/>
<Description
Class="site-dec"
Name="The Shown Price is only an estimate and may increase or decrease based on demand and extent of work"
/>
{pCR.activeAddOns.map((service, index) => (
<Badge color="info" pill>
{service.title}
</Badge>
))}
</div>
</Container>
</section>
);
};
Solution 1:[1]
You can achieve this by using componentDidUpdate
life cycle function in your component class. As per the docs
componentDidUpdate() is invoked immediately after updating occurs. This method is not called for the initial render.
Means, whenever the state of the component will change, the componentDidUpdate
code block will be called. So we can place an if condition in the block to compare the new state with the previous state, can calculate total and recommit it to the state. Code ?
class MyComponent extends React.Component {
constructor() {
super();
this.state = {
hours: 0,
total: 0,
ratePerHour: 10
};
}
componentDidUpdate(prevProps, prevState) {
if (prevState.hours !== this.state.hours) {
// Calculate total
this.setState({
total: this.state.total + this.state.hours * this.state.ratePerHour * Math.PI
}
}
}
render() {
return <AnotherComponent />;
}
}
Plus it is important to note that (ref: docs)
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.
In case of any other query, please feel free to reach out in the comments.
Solution 2:[2]
It's been a minute since I've worked with newer React features but when I can I use useEffect
in my functional components. The second parameter is the the variable you want to watch for changes. If you don't supply a second parameter it'll run similar to componentDidMount and componentDidUpdate. An example of possible use:
import React, { useState, useEffect } from 'react';
function Example() {
const [count, setCount] = useState(0);
const [test, setTest] = useState('');
// Specify to watch count because we have more than one state variable
useEffect(() => {
// Update the document title using the browser API
document.title = `You clicked ${count} times`;
}, [count]);
return (
<div>
<p>You clicked {count} times</p>
<button onClick={() => setCount(count + 1)}>
Click me
</button>
</div>
);
}
Here's some of their documentation: https://reactjs.org/docs/hooks-effect.html
Solution 3:[3]
In my case, even when I added the second argument to useEffect
which is an array of dependencies. It is running every time the component mounts instead of only if the value changes and I guess this is because I initialized my state variable like so
const[myStateVariable, setMyStateVariable] = React.useState('');
so I had to make this condition in my useEffect
function
React.useEffect(() => {
if(myStateVariable !==''){
getMyData()
}
}, [myStateVariable]);
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
Solution | Source |
---|---|
Solution 1 | Moiz Husnain |
Solution 2 | Dillan Wilding |
Solution 3 | hakima maarouf |