Search code examples
reactjsaxiosdrop-down-menu

React Dropdown: how to correctly use a selection to call an API endpoint


I'm learning (and loving) React, but I'm encountering some difficulties with the basics. Hoping someone can help. I'm trying to use a dropdown (React-Select) to load new data in the site. The problem is that I have to select the dropdown option twice in order to get the right data to load. I understand this is because React is asynchronous, but still not sure how to fix. I have read other posts here, but I cannot seem to use their suggestions to solve my problem.

The dropdown is dynamically populated from a list of objects from the database, like this:

const [options, setOptions] = useState([]);
const [selectedOption, setSelectedOption] = useState(null);

const labelOptionsProcessed = []
    options.map(item => {
        let tmpObj = {
            value: item
            label: item
        }
        labelOptionsProcessed.push(tmpObj)
    });

Then the dropdown is like this:

<div className = 'productList'>
      <h5>list of Products</h5>
           <Select 
             options={labelOptionsProcessed}
             onChange={handleSelectChange}
            />
 </div>

The "onChange" event calls "handleSelectChange", which looks like this:

const handleSelectChange = (event) => {
      setSelectedOption(event.value);
      loadData();   <====== i believe the problem is here 
    };

The loadData() function works correctly when the page loads the first time. but not when the user calls another "option" from the dropdown.

here is the loadData() function:

function loadData() {
    axios.get('/rawdata', {params: {p: selectedOption}})
      .then(res => {
        setRawData(res.data.records)
        setLoaded(true);
        })
    };

My useEffect call looks like this:

useEffect(() => {
      loadData()
      }, [selectedOption]);

I'm sure that I've made / overlooked some rookie mistakes. i've tried to simplify the code here to convey the essence of what is happening. Appreciate anyone who can provide some assistance. Thank you.


Solution

  • The problem seems to lie in the loadData function, which will not be updated when the selectedOption changes.

    One options to solve this is to wrap this function in useCallback like this:

    const loadData = React.useCallback(
      () => {
        axios.get('/rawdata', {params: {p: selectedOption}})
          .then(res => {
            setRawData(res.data.records)
            setLoaded(true);
          })
      },
      [selectedOption]
    )
    

    This will create a new instance of the loadData function every time the parameter selectedOption changes.

    Another option would be to provide the selectedOption as a parameter:

    function loadData(selectedOption) {
        axios.get('/rawdata', {params: {p: selectedOption}})
          .then(res => {
            setRawData(res.data.records)
            setLoaded(true);
            })
        };
    
    useEffect(() => {
          loadData(selectedOption)
       }, 
       [selectedOption]
    );
    

    In any case, you can remove the call to loadData from handleSelectChange - your useEffect will automatically trigger a reload when the selectedOption is changed.