Search code examples
reactjstypescriptreact-bootstrap

Populate dropdown after http request using Typescript and React


I'm trying to populate a dropdown (specifically a FormControl as select since I'm using React Bootstrap) with some data I'm retrieving from my backend (in my case some names). The structure of the data is

{
  data: [
    {name: "name1"},
    {name: "name2"},
    ...
  ]
}

I can retrieve the data since I can map the result and put every name in an array but my dropdown is always empty. What am I doing wrong? this is my code:

useEffect(() => {
    fetch(`some/url`)
      .then(rsp => rsp.json())
      .then(data => namesArray = data.data.map(el => {  //data.data is correct, I'm sending the json this way
          return el.name;);
  });
return(
...
<Row>
   <Form.Label column sm={4} md={{ offset: 1 }} className="font-weight-bold">
      Names
   </Form.Label>
   <Col sm={8}>
     <FormControl
        size="sm"
        id="names-dropdown-"
        as="select"
        value={model}
        onChange={e => {
           setNames(e.target.value)  
        }}
       >
       {namesArray.map(el => (<option value={el}>{el}</option>))}
     </FormControl>
  </Col>
</Row>
...)

Solution

  • Since you are working with TypeScript as well, you will need to define the types for your component's state. Looking at the structure of the response from the API request, you should create an interface or type alias

    interface NameObj {
      name: string;
    }
    

    And then, you can make use of this interface to define the state:

    const [namesArray, setNamesArray] = useState<NameObj[]>([]);
    

    Now that you have defined the state, you will need to update the state when the response from the API request is returned. Since it seems like it is only called once when the component is loaded, you should set an empty array ([]) as the dependency array so that it will only be called when the component is mounted. You can read about the dependency array over here.

    useEffect(() => {
        fetch(`some/url`)
          .then(rsp => rsp.json())
          .then(data => setRequestData(data.data)
      }, []);
    

    And finally, on the return, you can keep the rest as it is, with the following changes. This will iterate through the namesArray state and render the options.

    {namesArray.map(({ name }) => (<option value={name}>{name}</option>))}