You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

React点赞功能触发两次数据库数据拉取的原因是什么?

问题原因

你遇到的两次数据库拉取问题是两个错误写法共同导致的:

  • 你为了实现点赞后切换电影的需求,额外加了render状态强制刷新组件,每次render变化都会触发依赖它的useEffect执行,走一遍全量拉取热门电影的逻辑
  • 如果你用的是React 18且项目开启了严格模式(默认新建项目都会开),开发环境下组件的副作用会被强制触发两次,用来检测逻辑缺陷,所以拉取请求就变成了两次

另外你当前的实现逻辑本身就有不合理的地方:热门电影列表只需要首次加载的时候拉取一次就存在本地了,完全不需要每次点赞都重新拉取全量数据,你是因为把index声明成了普通变量而非React状态,修改后无法触发组件渲染,才用了强制刷新的错误写法。

修复方案

  1. 删掉冗余的render状态,把随机电影索引改成React状态,点赞后直接更新索引触发渲染切换电影,不需要重新拉取数据
  2. 修复useEffect的依赖,只在组件首次挂载的时候拉取一次热门电影列表
  3. 修复状态更新的闭包问题,拉取数据后用函数式写法更新电影列表
  4. 补充你拉取数据时缺失的movieGenre字段,避免后续调用movie.movieGenre.split时报错

修改后可运行代码

import React, { useState, useEffect } from 'react';
import './App.css';
import firebase from 'firebase/compat/app';
import 'firebase/database';
import 'firebase/firestore';
import './Menu/Menu.css';

function RateMovies() {
    const popularMoviesRef = firebase.database().ref("/popular_movies");
    const [popularMovies, setPopularMovies] = useState([]);
    // 把索引做成状态,修改后自动触发渲染
    const [currentMovieIndex, setCurrentMovieIndex] = useState(
        Math.floor(Math.random() * 1001)
    );

    const auth = firebase.auth();
    const db = firebase.firestore();
    const user_id = auth.currentUser?.uid;

    // 只在首次挂载时拉取一次热门电影列表
    useEffect(() => {
        popularMoviesRef.once("value").then(function(snapshot){
            const newArray = []
            snapshot.forEach(function(childSnapshot){
                const key = childSnapshot.key;
                const data = childSnapshot.val();
                newArray.push({ 
                    movieTitle: data.movie_title, 
                    moviePoster: data.movie_poster, 
                    movieGenre: data.movie_genre // 补充分类字段,避免后续调用split报错
                })
            });
            // 用函数式更新避免闭包陷阱
            setPopularMovies(newArray)
        });
    }, []);

    const movie = popularMovies[currentMovieIndex];

    function likedMovie() {
        if (!movie || !user_id) return;
        const genres = movie.movieGenre.split(',');

        db.collection('users').doc(user_id).update({
            "Rated.liked": firebase.firestore.FieldValue.arrayUnion({
                movieTitle: movie.movieTitle, 
                moviePoster: movie.moviePoster, 
             })
        }).then(function(){
            // 直接更新索引状态切换电影,不需要重新拉数据
            setCurrentMovieIndex(Math.floor(Math.random() * 1001))
        });
    }
    
    return (
        <div className="rate-background">
            <div className="rate-title"> {movie?.movieTitle} </div>
            <button onClick={likedMovie}> Like</button>
            <img className="rate-image" src={movie?.moviePoster} />
        </div>
    )
} 

export default RateMovies;

补充说明

如果开发环境还有两次执行的情况,属于React严格模式的正常检测行为,打包到线上环境就会自动消失,不需要额外处理。

内容的提问来源于stack exchange,提问作者Kris

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.26 06:45:03