1

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>
...)

2 Answers 2

2

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>))}
Sign up to request clarification or add additional context in comments.

Comments

1

You may want to use the useState hook. When you're extracting the data from the network request you could do something like:

  const [ requestData, setRequestData] = useState(0);

....

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

Then in your select/option

  <FormControl
        size="sm"
        id="names-dropdown-"
        as="select"
        value={model}
        onChange={e => {
           setNames(e.target.value)  
        }}
       >
       {requestData? requestData.map(el => (<option value={el}>{el}</option>))}
                   : <p>Loading</p>}
     </FormControl>

This is a general structure an approach, you need to check the var containing the data is not empty when mapping. When the network calls finishes it will use the useState hook to rerender with the data that's now obtained.

I may have got the exact syntax wrong. It's hard to do without a sandbox.

4 Comments

I tried it but it doesn't work. I can console.log(data.data) but when I console.log(requestData) it is empty
Update your question with what you've tried.If possible can you create a codepen or a sandbox so we can run your code
I've updated my answer slightly: .then(data => setRequestData(data.data))
Thanks but I also tried the other answer and it worked!! I think it was a Typescript problem (grr)

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.