Reputation: 55
I am working on a react components which populates a "select" menu drop down with a list of countries. I am trying to implement the first load using the "useEffect" hook.
This is what im doing. I get the reference of the "select" menu :
let countryMenu = document.getElementById("countryList");
let cityMenu = document.getElementById("cityList");
And then a foreach loop gets the names of the countries and appends them to the menu. This happens inside the "useEffect"
useEffect (()=>{
/* Fetch the list of countries */
listOfCountryObjects = (Country.getAllCountries())
/* Convert the list into a freindly list fo the options menu */
/* Load the countries list into the an array */
listOfCountryObjects.forEach(element => {
let option = new Option(element.name,element.name);
countryMenu.appendChild(option);
});
However, I debugged the application and observed that the "countryMenu" is null when the "foreach" loop is being executed. This leads to errors saying "Uncaught TypeError: Cannot read properties of null (reading 'appendChild')"
I am guessing that since the DOM isn't loaded before the "useEffect" runs, the "getElementbyID" returns "null".
What do you guys think? What's the best way to solve this?
Upvotes: 0
Views: 54
Reputation: 84902
Direct manipulation of the dom should be your very last resort in react. React has no idea that you're doing so, and so it cannot take your changes into account. Instead, what you're trying to do can be done with standard react practices. Get the data, then set state to rerender, then use that data in your component.
const Example = () => {
const [countries, setCountries] = useState([]);
useEffect(() => {
const loadCountries = async () => {
const newCountries = await Country.getAllCountries();
setCountries(newCountries);
};
loadCountries();
}, []);
return (
<div>
<select id="countryList">
{countries.map((country) => (
<option key={country.name} value={country.name}>
{country.name}
</option>
))}
</select>
</div>
);
};
Upvotes: 1