Reputation: 101
I am getting
Error: Maximum update depth exceeded. This can happen when a component repeatedly calls setState inside componentWillUpdate or componentDidUpdate. React limits the number of nested updates to prevent infinite loops.
But what I read I should be able to call setState inside componentDidMount without errors.
class MyComponent extends Component {
constructor(props) {
super(props);
this.state = {
matchtedProducts: [],
products: [],
}
}
async componentDidMount() {
try {
const products = await getProducts()
this.setState({ products })
} catch(err) {
console.log(err)
}
}
componentDidUpdate() {
const productColor = this.props.size.trim().toLowerCase()
const productSize = this.props.color.trim().toLowerCase()
const matches = []
this.state.products.map(product => {
const title = product.title
const titleSpliitet = title.split(',')
let color = titleSpliitet[1].trim().toLowerCase()
let size = titleSpliitet[2].trim().toLowerCase()
if(color == productColor && size == productSize) {
matches.push(product)
}
})
this.setState({matchtedProducts: matches})
}
render() {
return (<div></div>)
}
}
Upvotes: 2
Views: 12965
Reputation: 29
I got the same error.In the use effect method, i fetched the data from the backend using axios and I updated the states. But before updating the states I didn't convert the json data to data type of the state which is why it lead to this error.
Wrong code :
Useeffect(() => {
fetch
.then((res) =>{
setDate(res.data.date)
})
})
Correct code :
Useeffect(() => {
fetch
.then((res) =>{
setDate(new Date(res.data.date))
})
})
Upvotes: 1
Reputation: 814
This happens because each setState triggers a render and then a componentDidMount again, which basically causes an infinite loop. And to stop that loop, You need to set some conditions, to prevent the render all over again, for instance
componentDidUpdate(previousProps, previousState) {
if (previousProps.data !== this.props.data) {
this.setState({/*....*/})
}
}
Upvotes: 5
Reputation: 18602
it seems that you want to change the state when the props changes to filter some products.
I remove componentDidUpdate
code and add a method in the component to do the filtering and I would call that method from the parent component
class MyComponent extends Component {
constructor(props) {
super(props);
this.state = {
matchtedProducts: [],
products: [],
}
}
async componentDidMount() {
try {
const products = await getProducts()
this.setState({ products })
} catch(err) {
console.log(err)
}
}
updateMatches = () => {
const productColor = this.props.size.trim().toLowerCase()
const productSize = this.props.color.trim().toLowerCase()
const matches = []
this.state.products.map(product => {
const title = product.title
const titleSpliitet = title.split(',')
let color = titleSpliitet[1].trim().toLowerCase()
let size = titleSpliitet[2].trim().toLowerCase()
if(color == productColor && size == productSize) {
matches.push(product)
}
})
this.setState({matchtedProducts: matches})
}
render() {
return (<div></div>)
}
}
and in the parent component
changeSizeAndColor = () => {
//note that I called updateMatches of MyComponent
this.setState({color : ... , size : ...} , () => this.myComponent.updateMatches());
}
render() {
return <MyComponent ref={ref => this.myComponent = ref} color={...} size={...}/>
}
Upvotes: 1
Reputation: 2292
I think you have to pass prevProps
and/or prevState
as parameter(s) of the componentDidUpdate
, and execute the code only if a prop or a property of the state has changed,
Example:
componentDidUpdate(prevProps, prevState) {
// if the property count of the state has changed
if (prevState.count !== this.state.count) {
// then do your code
}
}
Docs : https://en.reactjs.org/docs/react-component.html#componentdidupdate
Upvotes: 1