这是我的函数代码:
function Detail() {
const { id } = useParams();
const [movie, setMovie] = useState();
useEffect(() => {
// Grab the movie info from db
db.collection("movies")
.doc(id)
.get()
.then((doc) => {
if (doc.exists) {
// save the movie to the state
setMovie(doc.data());
} else {
// redirect to home page
console.log("no such document in firebase ?");
}
});
}, [id]);
return (
<Container>
<Background>
<img alt=" background" src={movie.backgroundImg} />
</Background>
<ImageTitle>
<img alt="title" src={movie.titleImg} />
</ImageTitle>
<SubTitle>{movie.subtitle}</SubTitle>
<Description>{movie.description}</Description>
</Container>
);
}
这里一切正常,但是当我运行应用程序时,出现 TypeError: cannot read property 'backgroundImg' of undefined
经过几个小时的调试和研究,我发现问题在于,函数在没有时间从数据库中获取数据之前就开始寻找数据。
这里的解决方案是什么?我知道异步函数,但以前从未使用过。
答案 0 :(得分:0)
UseEffect 在渲染后和值 id 值改变时执行
function Detail() {
const { id } = useParams();
const [movie, setMovie] = useState();
useEffect(() => {
// Grab the movie info from db
const unsubscribe=db.collection("movies")
.doc(id)
.get()
.then((doc) => {
if (doc.exists) {
// save the movie to the state
setMovie(doc.data());
} else {
// redirect to home page
console.log("no such document in firebase ?");
}
});
return ()=>{
//clean up function to unsubscribe to firestore changes
unsubscribe();
}
}, [id]);
return (
<Container>
//render only if movie exists
{
movie ? <div>
<Background>
<img alt=" background" src={movie.backgroundImg} />
</Background>
<ImageTitle>
<img alt="title" src={movie.titleImg} />
</ImageTitle>
<SubTitle>{movie.subtitle}</SubTitle>
<Description>{movie.description}</Description>
</div>
: <p>...loading</p>
}
</Container>
);
}
答案 1 :(得分:0)
您可以在 react 中使用条件渲染并基于 movie
渲染不同的组件
return (
<Container>
{movie?
<React.Fragment>
<Background>
<img alt=" background" src={movie.backgroundImg} />
</Background>
<ImageTitle>
<img alt="title" src={movie.titleImg} />
</ImageTitle>
<SubTitle>{movie.subtitle}</SubTitle>
<Description>{movie.description}</Description>
</React.Fragment>
: <p>loading from firebase</p>}
</Container>
);
答案 2 :(得分:0)
您可能需要一些加载状态来控制内容是否可用,这是重构后的代码:
ps:如果它不起作用,请检查您的日志,以便我们查看错误
function Detail() {
const { id } = useParams();
const [loading, setLoading] = useState(false)
const [movie, setMovie] = useState();
useEffect(() => {
setLoading(true)
async function getMovie(id) {
try {
const doc = await db.collection("movies")
.doc(id)
.get()
if (doc.exists()) {
setMovie(doc)
}
}
catch (err) {
console.log(err)
}
}
getMovie(id)
setLoading(false)
}, []);
return (
<Container>
{!loading && (
<>
<Background>
<img alt=" background" src={movie.backgroundImg} />
</Background>
<ImageTitle>
<img alt="title" src={movie.titleImg} />
</ImageTitle>
<SubTitle>{movie.subtitle}</SubTitle>
<Description>{movie.description}</Description>
</>
)}
</Container>
);
}
答案 3 :(得分:0)
在 React 中,永远不要假设请求将被处理并且信息将存在或 React 将在请求完成处理之前呈现。所以你总是想使用 &&
运算符
function Detail() {
const { id } = useParams();
const [movie, setMovie] = useState();
useEffect(() => {
// Grab the movie info from db
db.collection("movies")
.doc(id)
.get()
.then((doc) => {
if (doc.exists) {
// save the movie to the state
setMovie(doc.data());
} else {
// redirect to home page
console.log("no such document in firebase ?");
}
});
}, [id]);
return (
{movie &&
<Container>
<Background>
<img alt=" background" src={movie.backgroundImg} />
</Background>
<ImageTitle>
<img alt="title" src={movie.titleImg} />
</ImageTitle>
<SubTitle>{movie.subtitle}</SubTitle>
<Description>{movie.description}</Description>
</Container>}
);
}