React升级后点击按钮不渲染更新总票数问题求助
React投票组件问题修复:页面不更新+Supabase返回data为null
核心问题分析
- Supabase更新后返回data为null:Supabase的
update方法默认不返回修改后的数据,必须显式添加.select()才能获取更新后的行记录。 - 页面票数不更新:
- 计算新票数时依赖了不会自动更新的
questionDataprops(父组件传入后无实时同步),而非本地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
相关产品推荐
相关产品推荐

