我已经试着调试这个问题几个小时了,但是我似乎一辈子都无法修复它。我正在尝试创建一个toast组件,每当创建一个toast时,它就会在列表中显示自己。它工作得很好,直到我尝试实现一个系统,在3秒后从列表中删除toast。
const Toast = (props) => {
const [active, setActive] = useState(false)
const { removeToast } = useToast()
const timerRef = useRef(null)
const timer2Ref = useRef(null)
useEffect(() => {
if (active) return; // attempt to prevent multiple timers from being created
setActive(true)
timerRef.current = setTimeout(() => {
setActive(false)
timer2Ref.current = setTimeout(() => { // Second timeout to remove the toast from the DOM after transition has finished
removeToast(props.id)
}, 300)
}, 3000)
return () => {
// If clear, it prevents the last toast in the list from being removed?
// If not cleared, strictmode causes issues (performs as expected with strictmode off)
clearTimeout(timer2Ref.current)
clearTimeout(timerRef.current)
}
}, [])
return (
<div className={`p-4 h-14 rounded-lg w-80 transition-all duration-300 flex-auto flex-0 ${props.className}`}
/*${active ? 'translate-y-0' : 'translate-y-96'} Removed to recognise issue more clearly */
>
{props.message}
</div>
)
}
export default Toast
不管我做什么,它似乎都不会像预期的那样工作。如果我清除了超时,它会像预期的那样工作,但列表中的最后一个吐司永远不会被删除。
如果我不清除超时(我相信你应该这样做,以防止内存泄漏),所有的toast被删除似乎在同一时间,我认为这是因为StrictMode,因为与StrictMode禁用它的所有功能,如预期的。但我宁愿不要删除StrictMode只是为了这个。
这里还有列表组件(我不认为这是问题所在)
const ToastList = () => {
const toastList = useSelector(state => state.toast.value)
useEffect(() => {
console.log(toastList)
}, [toastList])
if (toastList.length > 0) {
return (
<div className="flex flex-col-reverse pointer-events-none w-full z-50 fixed bottom-0 ">
{toastList.map((toast, index) => (
<Toast message={toast.message } icon={toast.icon} key={index} id={toast.id} className={`mx-auto my-3 ${toast.color}`} />
))}
</div>
)
}
}
export default ToastList
- 不确定是否相关,但我通过Redux将所有toast存储在一个数组中。
--
我在这里四处查看了一下,发现另一个post看起来像是OP有类似的问题。所以我尝试通过一个ref使用removeToast函数,就像在帖子中看到的那样,但这并没有解决问题。
我也尝试过使用一个自定义的useTimeout钩子,但也没有解决它。
我自己也没有主意,所以任何帮助都将不胜感激:)此外,我没有太多的React经验,所以我道歉,如果这里观察到的问题是由于我缺乏知识哈哈,如果你可以看到任何不良做法,这里只是让我知道,所以我不会在未来犯这些错误
1条答案
按热度按时间xtfmy6hx1#
我在您的代码中看到的唯一明显的问题是使用
toastList
数组索引作为React键。使用数组索引作为键通常被认为是React中的反模式。可接受的例外是数组从未发生变化。这显然是代码中的一个问题,因为吐司消息可以在任何时候添加到toastList
或从中删除。Map的toast.id
是React键的最佳选项,因为它是唯一标识吐司消息的内在属性。ToastList.jsx
Toast
组件***应***在超时到期之前提前卸载该组件的情况下清除任何运行超时。将超时入队逻辑拆分到一个useEffect
挂接中,该挂接具有适当的依赖关系和清除函数,以便在组件卸载时清除超时。演示