Afrikaans
Akan
Albanian
Amharic
Arabic
Armenian
Azerbaijani
Basque
Belarusian
Bemba
Bengali
Bihari
Bosnian
Breton
Bulgarian
Cambodian
Catalan
Cebuano
Cherokee
Chichewa
Chinese (Simplified)
Chinese (Traditional)
Corsican
Croatian
Czech
Danish
Dutch
English
Esperanto
Estonian
Ewe
Faroese
Filipino
Finnish
French
Frisian
Ga
Galician
Georgian
German
Greek
Guarani
Gujarati
Haitian Creole
Hausa
Hawaiian
Hebrew
Hindi
Hmong
Hungarian
Icelandic
Igbo
Indonesian
Interlingua
Irish
Italian
Japanese
Javanese
Kannada
Kazakh
Kinyarwanda
Kirundi
Kongo
Korean
Krio (Sierra Leone)
Kurdish
Kurdish (Soranรฎ)
Kyrgyz
Laothian
Latin
Latvian
Lingala
Lithuanian
Lozi
Luganda
Luo
Luxembourgish
Macedonian
Malagasy
Malay
Malayalam
Maltese
Maori
Marathi
Mauritian Creole
Moldavian
Mongolian
Myanmar (Burmese)
Montenegrin
Nepali
Nigerian Pidgin
Northern Sotho
Norwegian
Norwegian (Nynorsk)
Occitan
Oriya
Oromo
Pashto
Polish
Portuguese (Brazil)
Portuguese (Portugal)
Punjabi
Quechua
Romanian
Romansh
Runyakitara
Russian
Samoan
Scots Gaelic
Serbian
Serbo-Croatian
Sesotho
Setswana
Seychellois Creole
Shona
Sindhi
Sinhalese
Slovak
Slovenian
Somali
Spanish
Spanish (Latin American)
Sundanese
Swahili
Swedish
Tajik
Tamil
Tatar
Telugu
Thai
Tigrinya
Tonga
Tshiluba
Tumbuka
Turkish
Turkmen
Twi
Uighur
Ukrainian
Urdu
Uzbek
Vietnamese
Welsh
Wolof
Xhosa
Yiddish
Yoruba
Zulu
So I now wanna get rid here of DUMMY_MEALS
and instead fetch data from Firebase,
and we learned how that works.
For this, we can use the built-in fetch API,
which is built into the browser.
So this fetch function exists out of the box.
We could also use a custom HTTP hook,
for example, the one which we built in the HTTP section,
but here I will build it from scratch again.
Though, if you wanna use a custom hook,
or wanna build a custom hook,
or use some third-party HTTP hook package,
that would, of course, also be okay.
But I wanna build it from scratch here,
so I'll use, I'll write the fetch function from scratch,
and I want to fetch my meals data
when this component is loaded.
And we learned
that we can utilize the useEffect hook for this.
So we can import useEffect from react
to trigger a side effect like fetching data from the web
when some data changes
or, for example, when that component is loaded
for the first time.
So here I'll set up useEffect
and the effect function that should be triggered.
And then in there we can call fetch, like this.
Now, here we wanna send an HTTP request
to this meals node here,
so to this Firebase URL and then this meals node.
So the full URL is this Firebase URL,
which I grabbed here, and then meals.json.
.json is something Firebase-specific which we have to add.
So with that, we're sending a request
to this REST API endpoint, which Firebase exposes here,
and we're sending this request to fetch the meals.
We could configure this request, as you learned,
with a second argument passed to fetch,
but there we could, for example,
change the HTTP method and so on,
and we don't really wanna do that here.
We wanna stick to the default GET request, so this is fine.
Now, fetch returns a promise
since sending such a HTTP request is an asynchronous task.
Hence, we can add then here
to provide a function, this function here,
which is triggered when the request is done,
once we got a response.
Or we use async await.
For this, we need to turn this into async function
so that we can use the await keyword here.
But here we have to be careful,
and, actually, we even get a warning here.
At least, you might get one depending on your project setup.
The function you pass to useEffect
should not return a promise.
Instead, you learned that the function
you pass to useEffect
may return a cleanup function which can be executed.
You learned about that in the module
where I introduced useEffect.
That cleanup function should run synchronously though.
It should not return a promise or anything like this.
Hence, this overall function which we pass to useEffect
must not be turned into an async function.
Instead, if you wanna use async await instead of useEffect,
simply create a new function here, fetchMeals, like this,
and use async here and put your code, this line of code,
into this nested inner function,
and then just execute fetchMeals as part of useEffect.
By doing it that way, this function is still executed,
and you can still use async await,
but the overall useEffect function
does now not return a promise.
It's now not an async function
because we have not added async here,
which would not be allowed.
So that's a little workaround around that restriction,
which is absolutely fine though.
So now with that, we can use async await
to get a response here for fetching our meals.
And then you learned that for fetch, we can parse data.
We get our response,
responseData
by calling response.json,
which also returns a promise,
hence we also have the await keyword here.
So that's how we can get the responseData
which we're fetching,
and then we can utilize that responseData.
Now, the responseData we're getting in the case of Firebase,
and that's something Firebase-specific,
will always be an object where these ids here,
m1, m2, m3, m4,
will be keys,
and then the values for those keys will be nested objects
with those properties.
Hence, what we get back here,
responseData will be an object, and I want an array,
therefore we need to transform this.
So we can create a new constant loadedMeals,
which is an empty array,
and then we use a for/in loop
to go through all the keys in responseData,
so in this responseData object.
And the keys will be these ids here,
and the values for those keys
will then be the nested objects, as I just explained.
So here we then wanna reach out to loadedMeals
and push a new object into this initially empty array
where we, for example, set the id property.
We need to set id here
because we do expect our meals to have an id field.
So we should make sure that we transform the loaded data
such that we do have an id field.
And then we can set id equal to key
because, as I just mentioned, the key will be the id
of the individual meals we're fetching.
Now, we also need to set a name,
the description, and price fields.
And name can be pulled out of the responseData
for the given key.
With that, we access the nested object in there.
And then that nested object will have a name field,
as I just show you.
We're now accessing
this nested name field here, for example.
And we don't just do that for the name.
We also replicate this for the description here
and then also one more time for the price, like that.
With that, we're transforming the fetched data.
Now, we need to expose that fetched data
to, well, to the rest of our component,
and we wanna re-render the component
once the fetching is done
because that's an asynchronous task, which is only started
after the component loaded for the first time,
and therefore, initially, there will be no data,
and we wanna update the component once the data is there.
Now, when we have data that changes
and where a component should be re-evaluated
once it did change,
whenever we have a use case like this, we need state.
So we should also import useState here from react
and then set up some state in this component
by calling useState.
And here we initially might have an empty array
because this state will be our meals
and the setMeals state-updating function.
It's now the meals which I wanna use down there
instead of DUMMY_MEALS to render the MealItems.
And initially, that's an empty array, again,
but that will change once the loaded data is there.
And therefore, here, after this for loop,
once we filled our loadedMeals helper constant here
with the transformed data, I wanna call setMeals.
So I wanna call that state-updating function
and pass in the loadedMeals,
so that array which we populated here.
With that, we're setting the data,
and therefore then this component should update.
Now, for this useEffect function here,
currently our dependency array is an empty array.
So we have no dependencies,
which means this useEffect function, this function here,
will only run when the component was first loaded.
It will never run again thereafter.
And that sounds about right to me.
We, indeed, have no dependencies in there,
we're not using any external component-specific data,
we're not using any props in there or anything like that,
and therefore only running this
when the component is first loaded makes a lot of sense,
so we don't need to change this dependency's array.
And therefore, with all of that,
if we save this, we go back to our project, if I reload,
you see initially that list is empty,
but then the data arrives quickly.
Now, of course, we can show some loading spinner
or some loading state instead if we want to,
though currently the experience
also isn't too bad, I would argue,
but still, handling a loading state
and a potential error state
is something we're going to dive in next.
Can't find what you're looking for?
Get subtitles in any language from opensubtitles.com, and translate them here.