Reputation: 2051
I just started teaching myself ReactJS a few weeks ago and I'm stuck trying to figure out why my API gets consistently hit in an infinite loop after selecting a value from a dropdown. I have a search component called StateSearch.js that is being rendered in the StatePolicyPage.js component.
In StatePolicyPage.js I call <StateSearch parentCallback={this.callbackFunction} />
so that I can get the value the user picked from the dropdown and set the state. In StateSearch.js I'm passing the selected value using props.parentCallback(response.data)
The problem is that an infinite loop occurs for some reason and my Rails API keeps getting called over and over instead of just returning the data one time.
(StateSearch.js) search component
import React, { useState } from 'react'
import Select from 'react-select'
import makeAnimated from 'react-select/animated';
import axios from 'axios';
import statesJSON from '../../helpers/states';
// uses 'react-select'
export default function StateSearch(props) {
const [americanState, setAmericanState] = useState();
// if a state was selected from the dropdown
if (americanState) {
axios.get("http://localhost:3001/get_stuff", {
params: {
state: americanState.value
}
}).then(response => {
// the response back from the Rails server
if (response.status === 200) {
props.parentCallback(response.data); // send data back up to parent
}
}).catch(error => {
console.log("Error fetching the state ", americanState.value, error);
})
event.preventDefault();
}
// the dropdown select box for states.
return (
<div>
<Select
options={statesJSON}
placeholder="Select a State"
onChange={setAmericanState}
noOptionsMessage={() => 'Uh-oh nothing matches your search'}
className=""
components={makeAnimated()}
isSearchable
isClearable={true}
/>
</div>
)
}
(StatePolicyPage.js) the component that the search results should be passed to
import React, { Component } from 'react'
import Navigation from './Navigation';
import Container from 'react-bootstrap/Container';
import Row from 'react-bootstrap/Row';
import Col from 'react-bootstrap/Col';
import StateSearch from './search/StateSearch';
export default class StatePolicyPage extends Component {
constructor(props) {
super(props);
this.state = {
id: '',
stateName: '',
updatedAt: '',
createdAt: ''
}
}
callbackFunction = (childData) => {
console.log(childData);
this.setState({
id: childData.id,
stateName: childData.state_name,
updatedAt: childData.updated_at,
createdAt: childData.created_at
})
}
render() {
return (
<div>
<Navigation
isLoggedIn={this.props.loggedInStatus}
user={this.props.user}
handleLogoutClick={this.props.handleLogoutClick}
handleLogout={this.props.handleLogout}
/>
<Container>
{/* get the dropdown value from the StateSearch back */}
<StateSearch parentCallback={this.callbackFunction} />
<div>
<Row>
{ this.state.id }
</Row>
</div>
</Container>
</div>
)
}
}
Upvotes: 0
Views: 1748
Reputation: 121
This line looks to me like it could cause an infinite loop:
components={makeAnimated()}
I'm not entirely sure what this function is doing, but when passing functions to another component you can't directly invoke them.
Try replacing the above line with this:
components={makeAnimated}
or with this:
components={() => makeAnimated()}
Upvotes: 0
Reputation: 1473
Always use useEffect()
hook for asynchronous tasks.
useEffect(() => {
// if a state was selected from the dropdown
if (americanState) {
axios.get("http://localhost:3001/get_stuff", {
params: {
state: americanState.value
}
}).then(response => {
// the response back from the Rails server
if (response.status === 200) {
props.parentCallback(response.data); // send data back up to parent
}
}).catch(error => {
console.log("Error fetching the state ", americanState.value, error);
})
}
}, [americanState]);
Upvotes: 2