我有一个async
函数**(getDataFromDB)**,我在useEffect
中运行它。该函数从firestore获取数据。问题是我无法从firebase为数据设置状态。我获取了对数据的引用,我可以通过记录在控制台中看到数据,但setConfigs
不起作用,configs
状态仍然未定义。
// App
// imports
import { db } from "./firebase-config";
import {
query,
doc,
collection,
onSnapshot,
getDocs,
getDoc,
Firestore,
} from "firebase/firestore";
// from packages
import { useState, useEffect, useRef, useCallback } from "react";
import { Outlet } from "react-router-dom";
// sections
import Navbar from "./components/sections/Navbar";
import SearchBar from "./components/sections/Search-bar";
import TrendingBar from "./components/sections/Trending-bar";
// context
import ContextProviders from "./context-config";
// utils
import {
getGenres,
getTrendingData,
getMovies,
getTv,
onStartIntoDB,
getDataFromDB,
} from "./utils/fetchData";
// global constants
import { MAP_URL } from "./data/global-constants";
import { FirebaseError } from "firebase/app";
export default function App() {
// States
// genres and configs
const [genres, setGenres] = useState([]);
const [loading, setLoading] = useState("true");
// ==============================
// HERE IS CONFIGS STATE DECLARED
// ==============================
const [configs, setConfigs] = useState([]);
// movies data
const [trendingData, setTrendingData] = useState([]);
const [moviesData, setMoviesData] = useState([]);
const [popularMoviesData, setPopularMoviesData] = useState([]);
const [topRatedMoviesData, setTopRatedMoviesData] = useState([]);
const [upcomingMoviesData, setUpcomingMoviesData] = useState([]);
const [nowPlayingMoviesData, setNowPlayingMoviesData] = useState([]);
// tv data
const [tvData, setTvData] = useState([]);
const [airingTodayTvData, setAiringTodayTvData] = useState([]);
const [onTheAirTvData, setOnTheAirTvData] = useState([]);
const [popularTvData, setPopularTvData] = useState([]);
const [topRatedTvData, setTopRatedTvData] = useState([]);
// Refs
const preventEffect = useRef(true);
// ---------------------------------------
// Fetch data from api and push it into db
// ---------------------------------------
// configs
useEffect(() => {
onStartIntoDB(
preventEffect,
"getConfigs",
MAP_URL.configuration.base_url,
null,
null,
process.env.REACT_APP_API_KEY,
null,
"relating-data",
"configs"
);
}, []);
// genres for movies
useEffect(() => {
onStartIntoDB(
preventEffect,
"getGenres",
MAP_URL.genres.base_url,
MAP_URL.genres.media_type.movie,
null,
process.env.REACT_APP_API_KEY,
null,
"relating-data",
"genres-movie"
);
}, []);
// genres for tv
useEffect(() => {
onStartIntoDB(
preventEffect,
"getGenres",
MAP_URL.genres.base_url,
MAP_URL.genres.media_type.tv,
null,
process.env.REACT_APP_API_KEY,
null,
"relating-data",
"genres-tv"
);
}, []);
// trending movies
useEffect(() => {
onStartIntoDB(
preventEffect,
"getTrendingData",
MAP_URL.trendingMovies.base_url,
MAP_URL.trendingMovies.media_type.all,
MAP_URL.trendingMovies.time_window.week,
process.env.REACT_APP_API_KEY,
null,
"media",
"trending-movies"
);
}, []);
// movies
useEffect(() => {
onStartIntoDB(
preventEffect,
"getMovies",
MAP_URL.movies.base_url,
null,
null,
process.env.REACT_APP_API_KEY,
MAP_URL.movies.lang_and_page,
"media",
"movies"
);
}, []);
// tv
useEffect(() => {
onStartIntoDB(
preventEffect,
"getTv",
MAP_URL.tv.base_url,
null,
null,
process.env.REACT_APP_API_KEY,
MAP_URL.tv.lang_and_page,
"media",
"tv"
);
}, []);
// =================================================================
// Right below is the useEffect that should update the state with an
// async funtion.
// =================================================================
useEffect(() => {
async function getDataFromDB() {
const docRef = doc(db, "relating-data", "configs");
console.log(docRef); // => ya {converter: null, _key: ct, type:
// 'document', firestore: ih}
const docSnap = await getDoc(docRef);
console.log(docSnap); // => ya {converter: null, _key: ct, type:
// 'document', firestore: ih}
const dataArr = [];
dataArr.push(docSnap.data());
console.log(dataArr); // => [{…}] (and inside the object is the data:
// {change_keys: Array(53), images: {…}} )
setConfigs((prevData) => {
console.log("setConfigs executed!"); // => NOT EXECUTED!!!
const nextData = {
...prevData,
...dataArr,
};
return nextData;
});
}
getDataFromDB();
}, []);
// ==================================
console.log(configs); // => undefined
// ==================================
// genres
useEffect(() => {
async function g() {
const data = await getGenres(
MAP_URL.genres.base_url,
MAP_URL.genres.media_type.movie,
process.env.REACT_APP_API_KEY
);
setGenres(data);
}
g();
}, []);
// trending movies
useEffect(() => {
return async function () {
const data = await getTrendingData(
MAP_URL.trendingMovies.base_url,
MAP_URL.trendingMovies.media_type.all,
MAP_URL.trendingMovies.time_window.week,
process.env.REACT_APP_API_KEY
);
setTrendingData(data.results);
};
}, []);
// movies
useEffect(() => {
return async function () {
const data = await getMovies(
MAP_URL.movies.base_url,
process.env.REACT_APP_API_KEY,
MAP_URL.movies.lang_and_page
);
setMoviesData(data);
};
}, []);
// tv
useEffect(() => {
return async function () {
const data = await getTv(
MAP_URL.tv.base_url,
process.env.REACT_APP_API_KEY,
MAP_URL.tv.lang_and_page
);
setTvData(data);
};
}, []);
// ----------------------------------
// set popular movies
useEffect(() => {
setPopularMoviesData(moviesData[0]);
}, [moviesData[0]]);
// set top-rated movies
useEffect(() => {
setTopRatedMoviesData(moviesData[1]);
}, [moviesData[1]]);
// set now-playing movies
useEffect(() => {
setNowPlayingMoviesData(moviesData[2]);
}, [moviesData[2]]);
// set upcoming movies
useEffect(() => {
setUpcomingMoviesData(moviesData[3]);
}, [moviesData[3]]);
// ----------------------------------
// set airing-today tv
useEffect(() => {
setAiringTodayTvData(tvData[2]);
}, [tvData[2]]);
// set on-the-air tv
useEffect(() => {
setOnTheAirTvData(tvData[3]);
}, [tvData[2]]);
// set popular tv
useEffect(() => {
setPopularTvData(tvData[0]);
}, [tvData[0]]);
// set top-rated tv
useEffect(() => {
setTopRatedTvData(tvData[1]);
}, [tvData[1]]);
// ----------------------------------
return (
<ContextProviders configs={configs} trendingData={trendingData}>
<div className="App">
<Navbar />
<SearchBar />
<TrendingBar />
<Outlet />
</div>
</ContextProviders>
);
}
我尝试从async
函数外部设置状态,但是在这个例子中我调用了另一个async
,所以我真的不明白为什么它不设置状态。从API获取数据的操作也是一样的,例如如果使用fetch().then().then().catch(
)。我也尝试了.then()
链,但是没有任何结果。我在google上读了很多文章,但它不适用于我的情况,也许在我的整个代码中有一些东西?所以我的问题是如何正确地设置状态时,从一个firestore获取数据?
2条答案
按热度按时间db2dz4w81#
当前实现没有显式返回值,因此下一个状态值将是
undefined
。您需要返回下一个计算的状态值。更简洁地说:
tyg4sfes2#
问题是-设置的状态工作,但由于某些原因,没有触发另一个重新渲染,它结束了就像它没有被分配。然后我消费的状态,以触发另一个渲染,它的工作。所以我从这个案例的教训是要记住,useState是异步的,确保重新渲染,以查看状态。
以下是对我有效的解决方案: