I am new to react and have been having hard time implementing this dependent dropdown. I want to get the lists of states and filter out location that renders to the second dropdown. Below is what i tried implementing. The States and Location data is pulled from an API.
I was able to pull the states data but got stuck at implementing the dependent dropdown. Any help will be appreciated.
import React, { useState, useEffect } from 'react'
function NullView() {
// //API CALL
const [error, setError] = useState(null);
const [isLoaded, setIsLoaded] = useState(false);
const [items, setItems] = useState([]);
const [state, setState] = useState(null);
const [locations, setLocations] = useState([])
// console.log(count)
let loadLocations = (e) => {
e.preventDefault();
}
useEffect(() => {
fetch("/api/merchant/all/states/")
.then(res => res.json())
.then((result) => {
setIsLoaded(true);
setItems(result);
},
(error) => {
setIsLoaded(true);
setError(error);
}
)
if (state != null) {
fetch("/api/merchant/locations/2/")
.then(res => res.json())
.then((result) => {
setIsLoaded(true);
setLocations(result);
},
(error) => {
setIsLoaded(true);
setError(error);
}
)
}
}, [])
return (
<div>
<form onChange={loadLocations}>
<label for="states">Choose a State:</label>
<select id="states" name="states" onChange={(e) => setState(e.target.value)}>
<option value="">Select State</option>
{items.map(states => (
<option key={states.id} value={states.id}>{states.name}</option>
))}
</select>
<label for="location">Choose a Location:</label>
<select id="location" name="location" onChange={(e) => setLocation(e.target.value)}>
<option value="">Select Location</option>
{Location.map(location => (
<option key={location.id} value={location.id}>{location.name}</option>
))}
</select>
</form>
</div>
)
}
export default NullView
You can break the two fetches into separate useEffect
callbacks. The first useEffect
callback fetches on component mount and updates the "state" options while the second useEffect
has a dependency on the currently selected "state" value.
useEffect(() => {
fetch("/api/merchant/all/states/")
.then((res) => res.json())
.then((result) => setItems(result))
.catch((error) => setError(error))
.finally(() => setIsLoaded(true));
}, []); // <-- fetch once when component mounts
useEffect(() => {
if (state) {
fetch(`/api/merchant/locations/${state}`) // <-- compute request URL
.then((res) => res.json())
.then((result) => setLocations(result))
.catch((error) => setError(error))
.finally(() => setIsLoaded(true));
}
}, [state]); // <-- fetch when state updates
I believe you've also a typo in your render, Location
should likely be locations
state.
return (
<div>
<form onChange={loadLocations}>
<label for="states">Choose a State:</label>
<select
id="states"
name="states"
onChange={(e) => setState(e.target.value)}
>
<option value="">Select State</option>
{items.map((states) => (
<option key={states.id} value={states.id}>
{states.name}
</option>
))}
</select>
<label for="location">Choose a Location:</label>
<select
id="location"
name="location"
onChange={(e) => setLocation(e.target.value)}
>
<option value="">Select Location</option>
{locations.map((location) => ( // <-- render locations state
<option key={location.id} value={location.id}>
{location.name}
</option>
))}
</select>
</form>
</div>
);