Home > Back-end >  How do I use an asynchronous function to pass data to a Select component in a React class component?
How do I use an asynchronous function to pass data to a Select component in a React class component?

Time:11-04

I am trying to use MenuItem components with a React class component to display an array of strings as dropdown options in a Select component. In this snippet of code, I'm trying to retrieve these MenuItem components from the getGitRepoBranches(url) function call on line 11 and render them inside of my Select component:

1 {c.type === "git" ? <FormControl variant="outlined" size="small" style={{width: "20%", marginTop: "8px", marginRight: "0px"}}>
2      <InputLabel id="branch">Branch</InputLabel>
3      <Select
4          //error={!this.isGitRepoValid(c.url) && this.state.hasUserClickedSave}
5          //helperText={!this.isGitRepoValid(c.url) && this.state.hasUserClickedSave? INVALID_GIT_REPO_ERROR_MSG : ''}
6          labelId="branch-label"
7          id="demo-simple-select-helper"
8          label="Branch"
9          //onChange={(e) => this.editComponentHandler(e, i, "branch")}
10     >
11         {this.getGitRepoBranches(c.url)}
12     </Select>
13     {this.state.hasUserClickedSave ? (<FormHelperText style={{marginLeft: "0px"}} error>{INVALID_GIT_REPO_ERROR_MSG}</FormHelperText>) : null}
14 </FormControl> : null}

getGitRepoBranches() is retrieving data from an asynchronous API call fetchBranches, mapping the data to MenuItem components and returning them. It is defined like this:

getGitRepoBranches(url) {
    fetchBranches(url)
        .then((branches) => {
        if (branches.length > 0) {
            branches.map(branch => {
              return (
                <MenuItem value={branch}>
                  {branch}
                </MenuItem>
              )
            })
        }
         else
            return null
         })
    }

And fetchBranches is defined here:

1 export const fetchBranches = async (url: string): Promise<string[]> => {
2     let branches = <string[]>[];
3   ...
4         const URL: string = '/api/get_branches?'  
5             new URLSearchParams(queryParams).toString();
6 
7         try {
8             const response = await fetch(URL);
9             if (!response.ok) throw response.statusText;
10
11            const json = await response.json();
12            console.log("branches json:", json)
13            branches = createBranchesFromJSON(json);
14  ...
15    console.log("branches end of Api:", branches)
16    return Promise.resolve(branches);
17}

In fetchBranches, the console.log on line 15 shows that branches is an array of strings. As per this post's suggestion: Why is then not working on this function, I tried returning a promise in the fetchBranches function to use in conjunction with .then in getGitRepoBranches(). After I fetch this promise's data (the array of strings) and map it to MenuItem components in getGitRepoBranches(), I want to render the components on line 11 in the first code snippet. Why am I incorrectly using Promise.then to use data and render it to my Select component?

CodePudding user response:

Move your asynchronous data fetching out of the render. Kick it off when your component (or a parent component) mounts, and then update state (or props) when you get the data.

function MySelect ({ dataUrl }) {
  const [items, setItems] = useState([]);

  useEffect(() => {
    fetchData(dataUrl)
      .then(data => setItems(data));
  }, [dataUrl])

  return (
    <Select>
      { items.map(item => (
          <MenuItem value={item} key={item}>{item}</MenuItem>
      ))}
    </Select>
  );
}
<MySelect dataUrl="/some/api/endpoint" />
  • Related