React点击按钮仅能显示一次组件的问题排查与修复
修复React中Invoice组件仅能显示一次的问题
问题根源分析
- Props接收错误:原
Invoice组件未解构props,导致item.item._id的嵌套引用逻辑混乱,可能引发数据获取失败。 - 显示依赖错误:组件显示逻辑依赖
bill._id,关闭弹窗时执行setBill([])清空数据,后续即使触发重新渲染,也因bill._id不存在无法显示。 - Effect触发条件不足:
useEffect仅监听item变化,关闭弹窗后item未改变时,无法重新触发数据获取。 - 未定义变量错误:
useEffect中使用了未声明的open变量,导致状态切换逻辑失效。
修复方案:状态提升+明确显示控制
将数据获取和显示控制逻辑提升到父组件,子组件专注于渲染,符合React单向数据流原则,彻底解决重复触发问题。
父组件修改
import { useState } from 'react'; // 父组件中管理账单数据和显示状态 const [showInvoice, setShowInvoice] = useState(false); const [currentBill, setCurrentBill] = useState(null); // 点击按钮时获取账单数据并打开弹窗 const getBillDetails = async (item) => { const response = await allBills(item._id); setCurrentBill(response.data); setShowInvoice(true); }; // 渲染部分 <button onClick={() => getBillDetails(item)}>show</button> <Invoice bill={currentBill} isVisible={showInvoice} onClose={() => setShowInvoice(false)} />
Invoice子组件修改
import ReactDOM from 'react-dom'; import { useContext } from 'react'; import { ThemeContext } from './path-to-theme-context'; // 替换为实际路径 const Invoice = ({ bill, isVisible, onClose }) => { const Theme = useContext(ThemeContext); // 不满足显示条件时直接返回null if (!isVisible || !bill?._id) return null; return ReactDOM.createPortal( <div id="form__add"> {/* 点击遮罩关闭弹窗 */} <div className="backdrop" onClick={onClose}></div> <div className="invoice__header"> <div className="invoice__header__left"> <h1>Invoice</h1> <p>Invoice No: {bill._id}</p> <p>Invoice Date: {bill.createdAt}</p> <p>Payment Method: {bill.paymentMethod}</p> <p> <span>Customer Name: {bill.customer?.name}</span> <span>Customer Phone: {bill.customer?.phone}</span> </p> <table> <thead> <tr> <th>Product</th> <th>Quantity</th> <th>Price</th> <th>Total</th> </tr> </thead> <tbody> {bill.products?.map((product, index) => ( <tr key={index}> <td>{product.name}</td> <td>{product.quantity}</td> <td>{product.price}</td> <td>{product.quantity * product.price}</td> </tr> ))} </tbody> </table> </div> </div> </div>, document.getElementById('modal') ); }; export default Invoice;
修复关键点
- 状态提升:父组件统一管理数据获取和显示状态,避免子组件内部状态混乱。
- 明确显示控制:通过
isVisibleprop控制弹窗显示,不再依赖数据是否存在,确保每次点击都能触发显示。 - 健壮性优化:使用可选链
?.避免空值访问报错,减少潜在bug。 - 简化逻辑:关闭弹窗仅切换显示状态,无需清空数据,再次点击时重新获取最新数据。
内容的提问来源于stack exchange,提问作者dafaza
相关产品推荐
相关产品推荐

