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

React升级后点击按钮不渲染更新总票数问题求助

React投票组件问题修复:页面不更新+Supabase返回data为null

核心问题分析

  1. Supabase更新后返回data为null:Supabase的update方法默认不返回修改后的数据,必须显式添加.select()才能获取更新后的行记录。
  2. 页面票数不更新:
    • 计算新票数时依赖了不会自动更新的questionData props(父组件传入后无实时同步),而非本地state的最新值。
    • ProgressBar组件仍在使用旧的questionData,导致进度条同步失效。
    • 本地state更新逻辑依赖返回的data,但因data为null,state未触发更新。

具体修复步骤

1. 修复Supabase返回data为null的问题

在handleYes和handleNo的update语句末尾添加.select(),让Supabase返回修改后的行数据:

const handleYes = async () => {
  const { data, error } = await supabase
    .from('questions')
    .update({ votesYes: yes + 1, votesTotal: yes + no + 1 })
    .eq('id', questionData.id)
    .select() // 添加该行获取更新后的数据
  if (error) {
    console.log('errored: ' + error);
  }
  if (data) {
    setYes(data[0].votesYes);
  }
}

const handleNo = async () => {
  const { data, error } = await supabase
    .from('questions')
    .update({ votesNo: no + 1, votesTotal: yes + no + 1 })
    .eq('id', questionData.id)
    .select() // 添加该行
  if (error) {
    console.log(error)
  }
  if (data) {
    setNo(data[0].votesNo);
  }
}

2. 修复页面渲染更新问题

  • 优化state更新逻辑:直接基于当前state更新(实现即时页面反馈),同时保留数据库返回值作为兜底校准:
    // handleYes中可以改成:
    setYes(prevYes => prevYes + 1);
    // 请求失败时回滚state
    if (error) setYes(prev => prev - 1);
    // 用数据库返回值校准state
    if (data) setYes(data[0].votesYes);
    
  • 更新ProgressBar的数据源:将本地state的最新票数传给ProgressBar,替换旧的questionData:
    <ProgressBar 
      questionData={{
        ...questionData,
        votesYes: yes,
        votesNo: no,
        votesTotal: yes + no
      }} 
    />
    

3. 修复useEffect依赖项问题

将supabase添加到useEffect的依赖数组中,避免闭包导致的session监听失效:

useEffect(() => {
  supabase.auth.getSession().then(({ data: { session } }) => {
    setSession(session)
  })
  supabase.auth.onAuthStateChange((_event, session) => {
    setSession(session)
  })
}, [supabase]) // 添加supabase到依赖

修复后的完整组件代码

import { useState, useEffect } from "react"
import ProgressBar from "../ProgessBar"

const QuestionCard = ({ questionData, onDelete, supabase }) => {
  const [session, setSession] = useState(null);
  const [yes, setYes] = useState(questionData.votesYes);
  const [no, setNo] = useState(questionData.votesNo);

  useEffect(() => {
    supabase.auth.getSession().then(({ data: { session } }) => {
      setSession(session)
    })
    supabase.auth.onAuthStateChange((_event, session) => {
      setSession(session)
    })
  }, [supabase])

  const handleDelete = async () => {
    const { data, error } = await supabase
      .from('questions')
      .delete()
      .eq('id', questionData.id)
      .select()

    if (error) {
      console.log(error)
    }
    if (data) {
      console.log(data)
      onDelete(questionData.id)
    }
  }

  const handleYes = async () => {
    setYes(prev => prev + 1);
    const { data, error } = await supabase
      .from('questions')
      .update({ votesYes: yes + 1, votesTotal: yes + no + 1})
      .eq('id', questionData.id)
      .select()
    if (error) {
      console.log('errored: ' + error);
      setYes(prev => prev - 1);
    }
    if (data) {
      setYes(data[0].votesYes);
    }
  }

  const handleNo = async () => {
    setNo(prev => prev + 1);
    const { data, error } = await supabase
      .from('questions')
      .update({ votesNo: no + 1, votesTotal: yes + no + 1})
      .eq('id', questionData.id)
      .select()
    if (error) {
      console.log(error)
      setNo(prev => prev - 1);
    }
    if (data) {
      setNo(data[0].votesNo);
    }
  }

  const handlePollingResult = () => {
  }

  return (
    <div className="question-card">
      <h4>{questionData.question}</h4>
      <div className="polling-results">
        <h5>Total Votes: {yes + no}</h5>
      </div>
      <div>
        <ProgressBar 
          questionData={{
            ...questionData,
            votesYes: yes,
            votesNo: no,
            votesTotal: yes + no
          }} 
        />
      </div>
      <div className="buttons">
        {!session ? <i>Please Sign in to vote</i> : <i className="yes-btn" onClick={handleYes}>Yes</i>}
        {!session ? <i></i> : <i className="no-btn" onClick={handleNo}>No</i>}
        {!session ? <i></i> : <i className="delete-btn" id='delete-btn' onClick={handleDelete}>delete</i>}
        {!session ? <i></i> : <i className="polling-result-btn" onClick={handlePollingResult}>Results data</i>}
      </div>
    </div>
  )
}

export default QuestionCard

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.04 04:10:54