mateoc15
mateoc15

Reputation: 654

State not applied as expected when fetching data from API

I believe I'm misunderstanding how state works in React. I have a TextField as part of a Material UI Autocomplete component. The page is supposed to fetch new results each time the text changes to search the API with the new value. The simple output list at the bottom is updated as expected, but no results are ever populated in the list Autocomplete component. Here is how the Autocomplete is generally supposed to function, and here is my code (Sandbox link).

My questions are

  1. Why does the TextField not have the text value "basketball" on inital load if the label below does?
  2. Are my dependencies of inputText and setOptions the best way to load the data as I'm describing?

Ultimately I want to fetch a list of books, limited to top N results, and populate the rest of the form with data that comes back from the JSON results.

Thanks!

<Autocomplete
    id="ac1"
    options={options}

    onInputChange={(event, newValue) => { // text box value changed
        console.log("onInputChange start");
        setInputText(newValue);
        // if ((newValue).length > 3) { setInputText(newValue); }
        // else { setOptions([]); }
        console.log("onInputChange end");
    }}

    // SHOW THE TITLE IF THERE IS ONE
    getOptionLabel={(option) => option.volumeInfo && option.volumeInfo.title ? option.volumeInfo.title : "Unknown Title"}
    style={{ width: 600 }}
    renderInput={(params) =>
        <>
            <TextField {...params} label="Search for a book" variant="outlined"
                //ISBN - 10 or 13 digit
                value={inputText} // *** I WOULD EXPECT THIS TO BE SET TO "BASKETBALL" ON FIRST RENDER
                InputProps={{
                    ...params.inputProps
                }}
            />
        </>}
/>
useEffect(() => {
        async function fetchData() {
            const fetchString = `https://www.googleapis.com/books/v1/volumes?maxResults=3&q=${inputText}&projection=lite`;
            console.log(fetchString);

            const res = await fetch(
                fetchString,
            );

            const json = await res.json();

            // set the options to 
            (json && json.items) ? setOptions(json.items) : setOptions([]);
        }

        console.log("fetching data");
        fetchData();
        console.log("fetched data");
    }, [inputText, setOptions]);

Upvotes: 0

Views: 140

Answers (2)

mateoc15
mateoc15

Reputation: 654

Thank you to @Ignacio Elias for getting me halfway there, so thank you.

I'm sad to say (for the 1,000th time in my career) that the it was something really, really stupid. On the second line of the code below I needed to capitalize InputProps in the spread operator because while inputProps is a valid property of TextField, it's not the one I wanted. I changed "inputProps" to "InputProps" and I'm good now. I was mixing props InputProps and inputProps. Crazy that these two both exist as valid props.

                       InputProps={{
                            ...params.inputProps, // <----- RIGHT HERE
                            //autoComplete: 'new-password', // forces no auto-complete history
                            endAdornment: (
                                <InputAdornment position="end" color="inherit">
                                    {/* className={classes.adornedEnd} */}
                                    {/* {loading ? */}
                                    <CircularProgress color="secondary" size={"2rem"} />
                                    {/* : null} */}
                                </InputAdornment>
                            ),
                            style: {
                                paddingRight: "5px"
                            }
                        }}

Upvotes: 0

Ignacio Elias
Ignacio Elias

Reputation: 578

Try this

<TextField {...params} label="Search for a book" variant="outlined"
                //ISBN - 10 or 13 digit
                value={inputText} // *** I WOULD EXPECT THIS TO BE SET TO "BASKETBALL" ON FIRST RENDER
            />

Upvotes: 1

Related Questions