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

Firebase onAuthStateChange的unsubscribe失效问题求助

问题

我尝试调用unsubscribe()来停止onAuthStateChanged监听,但没生效。代码如下:

var unsubscribe = firebase.auth().onAuthStateChanged((user) => {
  unsubscribe()
  readCourses(user.uid) // 函数1:读取数据
  addElement(user) // 函数2:写入数据更新信息   
})

我希望函数1(对应代码里的lecturaCursos)只执行一次,所以想停止监听用户状态,但点击函数2的按钮时,函数1会再次执行,导致数据库信息重复。以下是完整相关代码:

var espacioforCards=document.getElementById('espacioCards')// Div 
var nombreCurso;
var descripcionCurso;
var obtenerNombreCurso=document.getElementById('obtener nombre curso')//button

function lecturaCursos(uid){
console.log('leyendo...datos')

var cursos = dbRef.ref("Usuarios").child(uid).child("cursos")
  
  cursos.on('value', (snapshot) => {
      if (snapshot.exists()){
        
         //spinner
          document.getElementById("spinner").style.visibility = "visible";
          snapshot.forEach((childSnapshot) => {
            crearTarjeta(childSnapshot.val().nombre,childSnapshot.val().descripcion)
          })
          
          document.getElementById("spinner").style.visibility = "hidden";   
      }else{
          console.log('No hay datos')
          document.getElementById("spinner").style.visibility = "hidden";   
      }     
    }); 
}

function crearCurso(userRef,nombreCurso,descripcionCurso){
    userRef.child('cursos').update({[nombreCurso]:{'nombre': nombreCurso, 'descripcion': descripcionCurso}})
 }

 function crearTarjeta(nombreCurso,descripcionCurso){
 let card = document.createElement("div")

 card.setAttribute("class","card")
 card.setAttribute('style', 'width: 15rem; margin:5px')
 card.setAttribute("id", nombreCurso);
 card.innerHTML+='<img src="img/nuevosm.jpg"class="card-img-top" alt="..."></img>'

 let cardbody = document.createElement("div")    
 cardbody.innerHTML+= '<h5 class="card-title">'+nombreCurso+'</h5>'
 cardbody.innerHTML+= '<p class="card-text">'+descripcionCurso+'</p>'  
 cardbody.innerHTML+='<a href="#" class="btn btn-primary">al curso</a>'

 card.appendChild(cardbody)
 espacioforCards.appendChild(card) 

 }
  function addElement (user) {    
 console.log('adding elements...........')    
 obtenerNombreCurso.addEventListener("click", function(){
  
  nombreCurso=document.getElementById('nombre del curso').value
   descripcionCurso=document.getElementById('descripcion del curso').value
   if(Boolean(nombreCurso) && Boolean(descripcionCurso)){      
          
    crearTarjeta(nombreCurso,descripcionCurso)
    let  userRef=dbRef.ref('Usuarios').child(user.uid)
     
    crearCurso(userRef,nombreCurso,descripcionCurso)
    //location.reload(true)
   }else{
    console.log('you must fill in')        
   }
  })
 }
解决方案

1. 替换持续监听器为单次读取

你当前的lecturaCursos用了cursos.on('value', ...),这会持续监听数据库cursos节点的变化——每次调用crearCurso写入新数据时,回调都会触发,导致重复创建卡片。

要实现仅读取一次数据,把on换成once:

function lecturaCursos(uid){
  console.log('leyendo...datos')
  var cursos = dbRef.ref("Usuarios").child(uid).child("cursos")
  
  // 用once替代on,仅执行一次数据读取
  cursos.once('value', (snapshot) => {
      if (snapshot.exists()){
          document.getElementById("spinner").style.visibility = "visible";
          snapshot.forEach((childSnapshot) => {
            crearTarjeta(childSnapshot.val().nombre,childSnapshot.val().descripcion)
          })
          document.getElementById("spinner").style.visibility = "hidden";   
      }else{
          console.log('No hay datos')
          document.getElementById("spinner").style.visibility = "hidden";   
      }     
  }); 
}

2. 修正unsubscribe调用时机

你现在在onAuthStateChanged回调里直接调用unsubscribe(),此时unsubscribe可能未完全初始化。正确做法是在确认用户存在并执行完逻辑后调用:

var unsubscribe = firebase.auth().onAuthStateChanged((user) => {
  if (!user) return; // 用户未登录时直接返回
  
  readCourses(user.uid)
  addElement(user)
  
  // 执行完必要逻辑后取消监听
  unsubscribe()
})

3. 避免重复绑定点击事件

每次onAuthStateChanged触发时,addElement都会给按钮绑定一次点击事件,多次触发会导致点击一次执行多次逻辑。添加标志位确保仅绑定一次:

// 新增标志位,防止重复绑定事件
let isEventBound = false

function addElement (user) {    
  console.log('adding elements...........')    
  if (isEventBound) return; // 已绑定则直接返回
  
  obtenerNombreCurso.addEventListener("click", function(){
    nombreCurso=document.getElementById('nombre del curso').value
    descripcionCurso=document.getElementById('descripcion del curso').value
    if(Boolean(nombreCurso) && Boolean(descripcionCurso)){      
      crearTarjeta(nombreCurso,descripcionCurso)
      let  userRef=dbRef.ref('Usuarios').child(user.uid)
      crearCurso(userRef,nombreCurso,descripcionCurso)
    }else{
      console.log('you must fill in')        
    }
  })
  
  isEventBound = true; // 标记为已绑定
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.02 21:31:08