我有一个按钮来显示使用dialog
html元素创建的模态,该按钮存储在一个条件的状态(thingsToRender
)中(在本例中,我在useEffect
钩子中模拟了该条件),然后如果someCondition
为true,则呈现thingsToRender
中的内容。问题是checkboxState
在handleRevealButtonClick
中似乎总是true
,即使在handleCheckboxChange
中它的实际值被更改为false
后,询问是否不得再次显示模态的复选框被选中。
似乎问题在于将button
函数handleRevealButtonClick
存储在thingsToRender
状态下,但我没有找到一个解决方案来满足我的需求,因为我需要以这种方式呈现按钮,因为在真实的的例子中,这个按钮包含在网格项中。那么,如何才能使该按钮不卡在checkboxState
的先前状态中呢?
下面是最小的可重复性示例:
import React, { useEffect, useRef, useState } from 'react'
function Test()
{
const [checkboxState, setCheckboxState] = useState(true);
const [someCondition, setSomeCondition] = useState(false);
const [thingsToRender, setThingsTorRender] = useState(<h1>Something</h1>);
const dialogRef = useRef(null);
const checkboxRef = useRef(null);
const handleCheckboxChange = () =>
{
const checkbox = checkboxRef.current;
if(checkbox.checked)
{
setCheckboxState(false)
}
else
{
setCheckboxState(true);
}
}
const handleRevealButtonClick = () =>
{
if(checkboxState)
{
const dialog = dialogRef.current;
dialog.showModal();
}
}
const handleCloseButtonClick = () =>
{
const dialog = dialogRef.current;
dialog.close();
}
useEffect(() =>
{
// Problem seems to be here
setThingsTorRender(<button onClick={handleRevealButtonClick}>Reveal modal</button>)
}, [])
return (
<div>
<dialog ref={dialogRef}>
<div>
<input type="checkbox" ref={checkboxRef} onChange={handleCheckboxChange}/>
<label>Not reveal again?</label>
</div>
<button onClick={handleCloseButtonClick}>Close</button>
</dialog>
{someCondition === true ? <h1>Some stuff</h1> : thingsToRender}
</div>)
}
export default Test;
**编辑:**为了阐明为什么按钮需要处于状态,我将展示更接近真实的示例的示例(请注意,thingsToRender
包含从firebase文档定义的网格元素):
const renderGrid = () =>
{
// query from Firebase
const grid = query.map((document, index) =>
<React.Fragment key={index}>
<div className='grid-item'>{document.data}</div>
<div className='grid-item'>{document.data}</div>
<div className='grid-item'>
<button onClick={handleRevealButtonClick}>Reveal modal</button>
</div>
</React.Fragment>
)
setThingsTorRender(grid)
}
useEffect(() =>
{
renderGrid();
}, [])
return (
<div>
{/* dialog */}
{someCondition === true ? <h1>Some stuff</h1> : <div className='grid-container'> {thingsToRender} </div>}
</div>)
1条答案
按热度按时间gzszwxb41#
不要在状态下存储JSX(通常没有必要)。相反,将JSX放入
return
中以避免将其置于state,然后使用state控制query
,以便在更改时重新渲染网格:如果你愿意,你可以把上面的内容放到它自己的
Grid
组件中,以使它更容易阅读,因为query
作为props传递给它。要理解为什么您当前的方法不起作用,您首先需要弄清楚当您的组件重新呈现时会发生什么。在每次重新渲染时,
Test
组件将再次执行,创建一个新的作用域,其中存储状态变量、函数等。在Test
组件中定义的重新创建。这意味着在组件的不同呈现中存在handleRevealButtonClick
回调函数的多个“版本”。handleRevealButtonClick
的每个版本只知道创建handleRevealButtonClick
的组件的特定渲染的状态值。您的问题是,您在
useEffect()
中设置的<button>
在组件的初始挂载时创建了一次(由于依赖项数组为空)。这意味着您设置的handleRevealButtonClick
的onClick
回调引用了在第一个渲染中创建的初始handleRevealButtonClick
,它只知道组件初始渲染中checkbox
状态的值,而不知道它可能被设置为的新值。