random_user_0891
random_user_0891

Reputation: 2051

ReactJS infinite loop after react-select dropdown selection

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

Answers (2)

aron fischer
aron fischer

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

Vaibhav
Vaibhav

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

Related Questions