0

The loop works when I don't assign regionOptions to regions.data. However when I do it throws the above error. I have no idea how else to proceed any pointers would be greatly appreciated - I am very new to all of this. Many thanks!

function AddOfficeForm(props: CreateOfficeFormProps): JSX.Element | null {

    let dropDownItems = [];
    let regionOptions: string | any[] = [];
    const region_id = uuidv4();

    // TODO: fetch actual available regions from API
    axios.get(ApiEndPoints.getAllRegionsForUser + firebaseContext.firebase.auth().currentUser?.uid)
        .then((regions: AxiosResponse<Array<string>>) => {
            regionOptions = regions.data;
        })
        .catch(function (error) {
            console.log(error);
        })
    history.push("/");

    const onTargetSelect = (selected: string) => {
        setSelectedRegion(selected);
    }

    for (let i = 0; i < regionOptions.length; i++) {
        dropDownItems.push(<Dropdown.Item key={regionOptions[i]} eventKey={i.toString()} onSelect={() => onTargetSelect(regionOptions[i])}>{regionOptions[i]}</Dropdown.Item>)
    }
  • At least closely related: [*Why is my variable unaltered after I modify it inside of a function? - Asynchronous code reference*](https://stackoverflow.com/questions/23667086/why-is-my-variable-unaltered-after-i-modify-it-inside-of-a-function-asynchron) – T.J. Crowder Jan 05 '21 at 10:17
  • Also at least closely related: [*How do I return the response from an asynchronous call?*](https://stackoverflow.com/questions/14220321/how-do-i-return-the-response-from-an-asynchronous-call) – T.J. Crowder Jan 05 '21 at 10:24

1 Answers1

0

I think TypeScript is complaining about that code because when the onSelect event handler is called, regionOptions[i] is evaluated then, and you've said that regionOptions[i] is string | any[] (it might be a string, or it might be an any[]). onTargetSelect requires that its argument be a string, but if regionOptions is any[], then regionOptions[i] is any, not string. Or it may be that combined with the fact that you reassign regionOptions after the loop.

I suspect you meant (string | any)[] (or Array<string | any> instead of string | any[], but even if so, you'd still have the issue that regionOptions[i] could be any rather than string. From your onTargetSelect parameter type, it should just be string[] (if you even give it an explicit type, which you often don't need to).

But the other problem is that regionOptions will be [] as of your loop and you'll never push anything to dropDownItems. Fundamentally, you shouldn't be using regionOptions outside the fulfillment handler on the axios call, because you don't have that data yet. (More in the answers to this question.) Once you do have the data, the idiomatic way to map those strings to Dropdown.Item instances is via map.

For instance:

function AddOfficeForm(props: CreateOfficeFormProps): JSX.Element | null {

    const region_id = uuidv4();

    const onTargetSelect = (selected: string) => {
        setSelectedRegion(selected);
    };

    // TODO: fetch actual available regions from API
    axios.get(ApiEndPoints.getAllRegionsForUser + firebaseContext.firebase.auth().currentUser?.uid)
        .then((regions: AxiosResponse<Array<string>>) => {
            // *** Build dropDownItems here
            const dropDownItems = regions.data.map((value, index) =>
                <Dropdown.Item key={value} eventKey={index.toString()} onSelect={() => onTargetSelect(value)}>{value}</Dropdown.Item>
            );
            // Do something with `dropDownItems` here
        })
        .catch(function (error) {
            console.log(error);
        });
    history.push("/"); // <== Unclear whether this should be here or in the fulfillment handler

You haven't shown what you want to do with dropDownItems, but note that your function can't return them (more in the answers to this question), because it returns before the axios call completes and gives you the data for them.

T.J. Crowder
  • 1,031,962
  • 187
  • 1,923
  • 1,875