Issue
In the App i fetch Data from Firebase/Firestore, parse it to a Interface and add the object to the State Array. After that i want to render it. But react wont render the array. I Have commented the Code that you can see what i thought it should do.
const Tab1: React.FC = () => {
let spiceArray: singleSpice[] = [];
interface singleSpice {
spice: string,
grams: number,
}
useEffect(() => {
//fetch the data --> Works well
async function loadData() {
const data = await getCollections();
// Add the Data to the Spicearray --> Works
data.forEach((e: any) => spiceArray.push(e));
}
// Trigger Function onComponentMount
loadData();
// This function will never log "Worked" even tho the loadData is Async
if(spiceArray.length > 0){
console.log("Worked")
}
})
return (
<IonPage>
<IonHeader>
<IonToolbar>
<IonTitle>Tab 1</IonTitle>
</IonToolbar>
</IonHeader>
<IonContent fullscreen>
<IonHeader collapse="condense">
<IonToolbar>
<IonTitle size="large">Tab 1</IonTitle>
</IonToolbar>
</IonHeader>
//Transfer the spiceArray to the next Child as Props --> Works
<CustomTab1 spices={spiceArray}/>
<ExploreContainer name="Tab 1 page" />
<IonButton onClick={() => console.log(spiceArray.length)}> Test me</IonButton>
</IonContent>
</IonPage>
);
};
export default Tab1;
Child
//Interface for Props
interface Props {
spices: Spice[];
}
//Interface to get access to inner Attributes of the SpiceObjectArray
interface Spice {
spice: string;
grams: number;
}
const CustomTab1: React.FC<Props> = ({spices}: Props) => {
return (
<IonList>
//Conditional Render
{spices.length > 0 && spices.map(entry => <IonItem id={entry.spice}>{entry.spice}</IonItem>)}
<IonButton onClick={() => console.log(spices)}>Test</IonButton>
</IonList>
);
};
export default CustomTab1;
Crazy Thing is. Right now when i F5 the IonicApp none of the spices is Displayed. But when i change the text inside the IoNButton on CustomTab1-Component and save the simple change the spices getting rendered. But if i press F5 to refresh the app everything is gone again.How can i make the app wait until the API delivers the data?
Solution
React doesn't rerender when variables change. You say you are passing the fetched object to the "state array" but spiceArray
is not a piece of react state. In a functional component, state is declared with useState.
When your page initially loads, there is no data, and you have the right idea to check if there is first any data before trying to map over/render it. But in order to get the component to rerender and thus recheck if spicesArray has anything in it you must use state and make a change to state.
const [spiceArray, setSpiceArray] = useState<singleSpice[] | null>(null)
useEffect(() => {
//fetch the data --> Works well
async function loadData() {
const data = await getCollections();
// Add the Data to the Spicearray --> Works
setSpiceArray(data)
}
// Trigger Function onComponentMount
loadData();
// This function will never log "Worked" even tho the loadData is Async
if (spiceArray.length > 0) {
console.log("Worked");
}
}, []);
your code should look something like this and change child component rendering logic to:
{spices && spices.map(entry => <IonItem id={entry.spice}>{entry.spice}</IonItem>)}
Keep in mind a couple of other things:
- if you want useEffect to run only on mount (which is usually the case when fetching data), you need an empty dependency array.
- console logging the spiceArray or checking if the spiceArray.length is not 0 will still not work in useEffect because state updates in react are async/ a request to update state for the next render. Therefor, changes will not be immediately reflected/ observable
Answered By - Shaynel
0 comments:
Post a Comment
Note: Only a member of this blog may post a comment.