渲染此功能组件的更好方法?
A better way to render this function component?
以下代码的目标是将数据从 firebase 实时数据库提取到名为 popularMovies 的数组中。 (实时数据库中的数据量为1000。)然后从该数组中随机选择一个索引,并将该索引处的电影数据显示在页面上。当用户点击喜欢的按钮时,该电影数据将存储在用户 ID 下的 firestore 文档中,并选择另一个随机索引来显示新电影。
下面的代码大部分都有效,但我注意到 console.log("运行!") 在页面加载时执行了 1000 次(正在读取的数据的大小)以及单击喜欢的按钮时。我希望理解为什么会出现这种情况,因为它在读取数据的 forEach 循环之外。
此外,单击一次按钮时,所有数据都会更新,但显示不会反映更改。但是,再次单击该按钮确实会随着显示再次更新数据(正如我预期的那样是第一次发生)。这继续下去,按钮仅在每隔一次按下后更新显示。我也想知道是什么导致了这个错误。
import React, { useState, useEffect } from 'react';
import './App.css';
import firebase from 'firebase/compat/app';
import 'firebase/database';
import 'firebase/firestore';
function RateMovies() {
const popularMoviesRef = firebase.database().ref("/popular_movies");
const [popularMovies, setPopularMovies] = React.useState([]);
var [render, setRender] = React.useState(1);
console.log("run!");
useEffect(() => {
popularMoviesRef.once("value", function(snapshot){
snapshot.forEach(function(childSnapshot){
var key = childSnapshot.key;
var data = childSnapshot.val();
setPopularMovies(currMovies => [...currMovies, {
key: key,
movieTitle: data.movie_title,
moviePoster: data.movie_poster,
movieYear: data.movie_year,
movieGenre: data.movie_genre,
movieRating: data.imdb_rating
}])
});
});
}, [render]);
var index = Math.floor(Math.random() * (1000 + 1));
var movie = popularMovies[index];
const auth = firebase.auth();
var db = firebase.firestore();
var user_id = auth.currentUser.uid;
function likedMovie() {
db.collection('users').doc(user_id).update({
"Rated.liked": firebase.firestore.FieldValue.arrayUnion({
key: movie.key,
movieTitle: movie.movieTitle,
moviePoster: movie.moviePoster,
movieYear: movie.movieYear,
movieGenre: movie.movieGenre,
movieRating: movie.movieRating,
}),
})
.then(function(){
console.log("Successfully updated!");
setRender(render++);
});
index = Math.floor(Math.random() * (1000 + 1));
movie = popularMovies[index];
}
return (
<div>
<p>Rate Movies Here</p>
<div> {movie?.movieTitle} </div>
<div> {movie?.movieYear} </div>
<br/>
<button onClick={likedMovie}> Like</button>
<button> Disike</button>
<br/>
<br/>
<img class="rate-image" src = {`${movie?.moviePoster}`} />
</div>
)
}
export default RateMovies;
您看到 console.log()
1000 次的原因是因为您的 forEach()
循环更新了 RateMovies()
中定义的状态变量 (popularMovies
)。每次状态改变时,React 都会重新渲染你的组件。
与其一次添加一个新项目,不如在 forEach
循环中创建一个新数组。这只会修改状态一次,这意味着组件应该只重新渲染一次。
尝试这样的事情:
useEffect(() => {
popularMoviesRef.once("value").then(function(snapshot){
var newArray = []
snapshot.forEach(function(childSnapshot){
var key = childSnapshot.key;
var data = childSnapshot.val();
newArray.push({
key: key,
movieTitle: data.movie_title,
moviePoster: data.movie_poster,
movieYear: data.movie_year,
movieGenre: data.movie_genre,
movieRating: data.imdb_rating
})
});
setPopularMovies([...popularMovies, ...newArray])
}));
}, [render]);
至于你的按钮没有重新呈现你想要的数据,我不是 100% 确定,但这可能与 JavaScript 处理承诺的方式有关。您 useEffect
中的 popularMoviesRef.once
调用可能与您的 db.collection('users').doc(user_id).update
同时发生。您可以通过将 console.log()
添加到 useEffect
函数来测试它,以尝试查看它是否在 "Successfully Updated!"
.
之前记录
看这里:
以下代码的目标是将数据从 firebase 实时数据库提取到名为 popularMovies 的数组中。 (实时数据库中的数据量为1000。)然后从该数组中随机选择一个索引,并将该索引处的电影数据显示在页面上。当用户点击喜欢的按钮时,该电影数据将存储在用户 ID 下的 firestore 文档中,并选择另一个随机索引来显示新电影。
下面的代码大部分都有效,但我注意到 console.log("运行!") 在页面加载时执行了 1000 次(正在读取的数据的大小)以及单击喜欢的按钮时。我希望理解为什么会出现这种情况,因为它在读取数据的 forEach 循环之外。
此外,单击一次按钮时,所有数据都会更新,但显示不会反映更改。但是,再次单击该按钮确实会随着显示再次更新数据(正如我预期的那样是第一次发生)。这继续下去,按钮仅在每隔一次按下后更新显示。我也想知道是什么导致了这个错误。
import React, { useState, useEffect } from 'react';
import './App.css';
import firebase from 'firebase/compat/app';
import 'firebase/database';
import 'firebase/firestore';
function RateMovies() {
const popularMoviesRef = firebase.database().ref("/popular_movies");
const [popularMovies, setPopularMovies] = React.useState([]);
var [render, setRender] = React.useState(1);
console.log("run!");
useEffect(() => {
popularMoviesRef.once("value", function(snapshot){
snapshot.forEach(function(childSnapshot){
var key = childSnapshot.key;
var data = childSnapshot.val();
setPopularMovies(currMovies => [...currMovies, {
key: key,
movieTitle: data.movie_title,
moviePoster: data.movie_poster,
movieYear: data.movie_year,
movieGenre: data.movie_genre,
movieRating: data.imdb_rating
}])
});
});
}, [render]);
var index = Math.floor(Math.random() * (1000 + 1));
var movie = popularMovies[index];
const auth = firebase.auth();
var db = firebase.firestore();
var user_id = auth.currentUser.uid;
function likedMovie() {
db.collection('users').doc(user_id).update({
"Rated.liked": firebase.firestore.FieldValue.arrayUnion({
key: movie.key,
movieTitle: movie.movieTitle,
moviePoster: movie.moviePoster,
movieYear: movie.movieYear,
movieGenre: movie.movieGenre,
movieRating: movie.movieRating,
}),
})
.then(function(){
console.log("Successfully updated!");
setRender(render++);
});
index = Math.floor(Math.random() * (1000 + 1));
movie = popularMovies[index];
}
return (
<div>
<p>Rate Movies Here</p>
<div> {movie?.movieTitle} </div>
<div> {movie?.movieYear} </div>
<br/>
<button onClick={likedMovie}> Like</button>
<button> Disike</button>
<br/>
<br/>
<img class="rate-image" src = {`${movie?.moviePoster}`} />
</div>
)
}
export default RateMovies;
您看到 console.log()
1000 次的原因是因为您的 forEach()
循环更新了 RateMovies()
中定义的状态变量 (popularMovies
)。每次状态改变时,React 都会重新渲染你的组件。
与其一次添加一个新项目,不如在 forEach
循环中创建一个新数组。这只会修改状态一次,这意味着组件应该只重新渲染一次。
尝试这样的事情:
useEffect(() => {
popularMoviesRef.once("value").then(function(snapshot){
var newArray = []
snapshot.forEach(function(childSnapshot){
var key = childSnapshot.key;
var data = childSnapshot.val();
newArray.push({
key: key,
movieTitle: data.movie_title,
moviePoster: data.movie_poster,
movieYear: data.movie_year,
movieGenre: data.movie_genre,
movieRating: data.imdb_rating
})
});
setPopularMovies([...popularMovies, ...newArray])
}));
}, [render]);
至于你的按钮没有重新呈现你想要的数据,我不是 100% 确定,但这可能与 JavaScript 处理承诺的方式有关。您 useEffect
中的 popularMoviesRef.once
调用可能与您的 db.collection('users').doc(user_id).update
同时发生。您可以通过将 console.log()
添加到 useEffect
函数来测试它,以尝试查看它是否在 "Successfully Updated!"
.
看这里: