0

I have this function which get a JSON array from an URL containing list of options that I want to show as option in my Autocomplete component.

function ShowMovies() {
    async function GetMovies() {
        movies_list = await fetch(url, {
            method: 'GET',
            headers: {
                'Accept': 'application/json',
                'authorization': token
            },
        }).then(response => movies_list = response.json());
    }
    GetMovies();

    return ( <Autocomplete multiple freeSolo disablePortal id = 'movies'
        name = 'movies'
        options = {
            movies_list
        }
        getOptionLabel = {
            (option) => option.movie_name
        }
        renderInput = {
            (params) => < TextField {
                ...params
            }
            label = 'New movies:' / >
        }
        />
    );
    export default ShowMovies;

However, this fails to load returned options and gives me below warning. Which is according to my understanding is because at the time I am binding this to the component the fetch request is still ongoing.

Warning: Failed prop type: The prop `options` is marked as required in `ForwardRef(Autocomplete)`, but its value is `undefined`.

How can I delay this binding until the request is completed?

Maven
  • 14,587
  • 42
  • 113
  • 174
  • There's ([still](https://stackoverflow.com/q/76271306/3001761)!) no rational reason to expect `movies_list` to be set. Please re-read https://react.dev/learn/synchronizing-with-effects, https://stackoverflow.com/q/14220321/3001761. Also I'd strongly recommend writing your JSX in a less idiosyncratic way. – jonrsharpe May 17 '23 at 18:08
  • Does this answer your question? [Get value from fetch in React](https://stackoverflow.com/questions/62374943/get-value-from-fetch-in-react) – jonrsharpe May 17 '23 at 18:08
  • `Prettier` is a nice helper to get your code readable and well formatted. It is working with zero configuration and even better configurable via code. If you are using VSCode it is also available as a plugin/extension. You can use it also via npm / yarn / package.json scripts, and of course many other ways. – ILCAI May 17 '23 at 19:48
  • When working with functional react components: Try not to rely on or use variables from the outer scope that should be mutable. Try to follow functional principles like `pure functions`, `immutability` to solve your problems. Try to think linear / functional / not in parallel scopes. try to never mutated a variable that is out of the scope you are currently operating in. – ILCAI May 17 '23 at 19:52

1 Answers1

1

On the first run this function will return the the <AutoComplete [...] /> component. Clearly movies_list is undefined, because it would eventually get populated asynchroniously. That HTTP call will surely take longer than the rendering.

Then you have to be aware of two other things:

  1. The function GetMovies will be defined again on every render / call of your component function which is just unnecessary.
  2. The call GetMovies() is not "awaited", and even worse: it is one of the worst places in a React Function component to place that call.

To show you a better way, let me rewrite your construct with JS - Pseudo code - it will show you the schematics and you can easily translate that into JavaScript.

function ShowMovies() {
    const [movies, setMovies] = useState([]);

    useEffect(() => {
        fetch('some url', {
            method: 'GET',
            headers: {
                'Accept': 'application/json',
                'authorization': 'some token'
            },
        }).then(response => response.json())
        .then(json => setMovies(json));
    }, []);

    return <Autocomplete
        multiple
        freeSolo
        disablePortal
        id="movies"
        name="movies"
        options={movies}
        getOptionLabel={(option) => option.movie_name}
        renderInput={(params) => <TextField {...params} label="New 
movies:" / >}
        />;
}

More details:

The fact, that you query further resources (via that http call) after the component has been rendered is called a "side effect" (not only) in react world. It shall happen in parallel to your rendering logic. The useEffect hook is perfectly suited for this kind of problem. Please read the documentation! Whatever ... used the useEffect hook in this way, with those parameters it just runs once after the component has rendered for the first time. That's the best moment to query for the data. When the response arrives you put it into a state (useState) object, which in turn forces the component to update (render again), but this time with the data at hand you just set.

I hope this is a good starting point.

Read the react hooks docs!

Watch some nice beginner react tutorials!

ILCAI
  • 1,164
  • 2
  • 15
  • 35