Sorry, folks. I ended up summarizing too much.
Let’s go:
The current App.js is set up to display only the ‘Search’ page, as shown below. The page is wrapped within another page called ‘CallApiProvider’ because through this page, I am using API Context, which I will talk about shortly.
import React from "react";
import Search from "./src/pages/Search";
import { CallApiProvider } from "./src/components/CallApiProvider";
export default function App() {
return (
<CallApiProvider>
<Search />
</CallApiProvider>
);
}
The idea of the ‘Search’ page is that when the app is opened, it should display a search field (the ‘Busca’ component), a movie preview (the ‘Preview’ component), and a horizontal list with the top 10 latest movies (the ‘MovieCarousel’ component).
The code for the ‘Search’ page is right below.
import React, { useContext } from "react";
import { ScrollView, FlatList, Text, ActivityIndicator } from "react-native";
import Busca from "../components/Busca";
import { EnviromentButton } from "../components/EnviromentButton";
import Preview from "../components/Preview";
import MovieCarousel from "../components/MovieCarousel";
import { ApiContext } from "../components/CallApiProvider";
import styles from "../styles/Search_styles";
function Search() {
const { details } = useContext(ApiContext);
if (details !== undefined) {
console.log(details.adult);
return (
<ScrollView style={styles.container}>
<Busca dica={"Type title, categories, years, etc"} />
<FlatList
data={details} //Precisa ser substituído pelo array de gêneros
renderItem={({ item }) => <EnviromentButton title={item.id} active />}
horizontal
showsHorizontalScrollIndicator={false}
contentContainerStyle={styles.genreList}
/>
<Text style={styles.label}>Today</Text>
<Preview />
<Text style={styles.label2}> Recommend for you</Text>
<MovieCarousel data={details} />
</ScrollView>
);
} else {
return (
<ScrollView style={styles.container}>
<ActivityIndicator style="large" />
</ScrollView>
);
}
}
export default Search;
To load movie information, I am making an API call through the ‘CallApiProvider’ page and distributing the API response using the API Context mentioned earlier. The code for the ‘CallApiProvider’ page is right below.
import React, { useState, useEffect, createContext } from "react";
import api from "../services/api";
export const ApiContext = createContext();
export const CallApiProvider = ({ children }) => {
const [details, setDetails] = useState(null);
useEffect(() => {
async function fetchDetails() {
try {
const { data } = await api.get("/trending/all/week?language=pt-BR");
const limitedData = data.results.slice(0, 10);
setDetails(limitedData);
} catch (error) {
console.error("Error fetching", error);
}
}
fetchDetails();
}, []);
return (
<ApiContext.Provider value={{ details }}>
{children}
</ApiContext.Provider>
);
};
Therefore, my goal is that whenever the ‘Search’ page is loaded, it checks whether the ‘details’ variable has already received the API information. If it hasn’t received the information yet, it will be ‘undefined,’ and in that case, I want the loading screen to be displayed.
The problem that is happening is that instead of the ‘IF’ block rendering the loading screen when ‘details’ is ‘undefined,’ it is proceeding as if ‘details’ has the API information, causing all the code dependent on that information to break.
The error that occurs in the app is: "TypeError: Cannot read property ‘adult’ of null."
But this error shouldn’t happen if the "IF" statement worked correctly…
2
Answers
Changing the answer after your update:
The problem is because "null" is different of "undefined"
so when you start your application for the first time the initial state of details is defined as null.
Just clear your state here:
from
to
It will solve your problem.
For suggestion, you can change your if statement too, and use like this:
details
isnull
notundefined
Change
details !== undefined
todetails
ordetails !== null