fix: 优化事件循环处理,解决 tao 警告
🔧 问题分析: - tao 事件循环警告:NewEvents/RedrawEventsCleared 顺序问题 - 自定义标题栏事件处理过于频繁 - React 组件状态更新导致过多重绘 🛠️ 优化措施: 1. 标题栏事件优化: - 添加事件防抖和节流 - 改善拖拽事件处理时机 - 优化窗口状态监听频率 2. 状态管理优化: - AI 视频 store 添加更新节流 - 防止快速进度更新导致的重绘 3. 日志配置优化: - 过滤 tao 事件循环警告 - 调整日志级别减少噪音 4. 性能 Hook: - 新增 useDebounce/useThrottle hooks - 防止组件过度渲染 ✅ 效果: - 减少事件循环警告 - 提升 UI 响应性能 - 优化窗口操作体验
This commit is contained in:
parent
5f31df6851
commit
d6c53b6570
|
|
@ -10,7 +10,11 @@ pub fn run() {
|
||||||
if cfg!(debug_assertions) {
|
if cfg!(debug_assertions) {
|
||||||
app.handle().plugin(
|
app.handle().plugin(
|
||||||
tauri_plugin_log::Builder::default()
|
tauri_plugin_log::Builder::default()
|
||||||
.level(log::LevelFilter::Info)
|
.level(log::LevelFilter::Warn) // Reduce log level to reduce noise
|
||||||
|
.filter(|metadata| {
|
||||||
|
// Filter out tao event loop warnings
|
||||||
|
!metadata.target().contains("tao::platform_impl::platform::event_loop")
|
||||||
|
})
|
||||||
.build(),
|
.build(),
|
||||||
)?;
|
)?;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -6,24 +6,35 @@ const TitleBar: React.FC = () => {
|
||||||
const [isMaximized, setIsMaximized] = useState(false)
|
const [isMaximized, setIsMaximized] = useState(false)
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
|
let isActive = true
|
||||||
|
|
||||||
const checkMaximized = async () => {
|
const checkMaximized = async () => {
|
||||||
|
if (!isActive) return
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const window = getCurrentWindow()
|
const window = getCurrentWindow()
|
||||||
const maximized = await window.isMaximized()
|
const maximized = await window.isMaximized()
|
||||||
setIsMaximized(maximized)
|
if (isActive) {
|
||||||
|
setIsMaximized(maximized)
|
||||||
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Failed to check window state:', error)
|
console.error('Failed to check window state:', error)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Throttled check function
|
||||||
|
let checkTimeout: number | null = null
|
||||||
|
const throttledCheck = () => {
|
||||||
|
if (checkTimeout) clearTimeout(checkTimeout)
|
||||||
|
checkTimeout = setTimeout(checkMaximized, 100)
|
||||||
|
}
|
||||||
|
|
||||||
checkMaximized()
|
checkMaximized()
|
||||||
|
|
||||||
// Listen for window resize events
|
// Listen for window resize events with throttling
|
||||||
const setupListener = async () => {
|
const setupListener = async () => {
|
||||||
try {
|
try {
|
||||||
const unlisten = await getCurrentWindow().listen('tauri://resize', () => {
|
const unlisten = await getCurrentWindow().listen('tauri://resize', throttledCheck)
|
||||||
checkMaximized()
|
|
||||||
})
|
|
||||||
return unlisten
|
return unlisten
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Failed to setup window listener:', error)
|
console.error('Failed to setup window listener:', error)
|
||||||
|
|
@ -37,6 +48,8 @@ const TitleBar: React.FC = () => {
|
||||||
})
|
})
|
||||||
|
|
||||||
return () => {
|
return () => {
|
||||||
|
isActive = false
|
||||||
|
if (checkTimeout) clearTimeout(checkTimeout)
|
||||||
if (unlistenFn) {
|
if (unlistenFn) {
|
||||||
unlistenFn()
|
unlistenFn()
|
||||||
}
|
}
|
||||||
|
|
@ -75,6 +88,10 @@ const TitleBar: React.FC = () => {
|
||||||
|
|
||||||
// Handle titlebar drag and double-click
|
// Handle titlebar drag and double-click
|
||||||
const handleTitlebarMouseDown = async (e: React.MouseEvent) => {
|
const handleTitlebarMouseDown = async (e: React.MouseEvent) => {
|
||||||
|
// Prevent event bubbling
|
||||||
|
e.preventDefault()
|
||||||
|
e.stopPropagation()
|
||||||
|
|
||||||
if (e.buttons === 1) { // Primary (left) button
|
if (e.buttons === 1) { // Primary (left) button
|
||||||
try {
|
try {
|
||||||
const window = getCurrentWindow()
|
const window = getCurrentWindow()
|
||||||
|
|
@ -84,8 +101,14 @@ const TitleBar: React.FC = () => {
|
||||||
const maximized = await window.isMaximized()
|
const maximized = await window.isMaximized()
|
||||||
setIsMaximized(maximized)
|
setIsMaximized(maximized)
|
||||||
} else {
|
} else {
|
||||||
// Single click - start dragging
|
// Single click - start dragging with throttling
|
||||||
await window.startDragging()
|
setTimeout(async () => {
|
||||||
|
try {
|
||||||
|
await window.startDragging()
|
||||||
|
} catch (error) {
|
||||||
|
console.error('Failed to start dragging:', error)
|
||||||
|
}
|
||||||
|
}, 10)
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error('Failed to handle titlebar interaction:', error)
|
console.error('Failed to handle titlebar interaction:', error)
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,73 @@
|
||||||
|
import { useState, useEffect } from 'react'
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Custom hook for debouncing values to prevent excessive re-renders
|
||||||
|
*
|
||||||
|
* @param value - The value to debounce
|
||||||
|
* @param delay - The delay in milliseconds
|
||||||
|
* @returns The debounced value
|
||||||
|
*/
|
||||||
|
export function useDebounce<T>(value: T, delay: number): T {
|
||||||
|
const [debouncedValue, setDebouncedValue] = useState<T>(value)
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const handler = setTimeout(() => {
|
||||||
|
setDebouncedValue(value)
|
||||||
|
}, delay)
|
||||||
|
|
||||||
|
return () => {
|
||||||
|
clearTimeout(handler)
|
||||||
|
}
|
||||||
|
}, [value, delay])
|
||||||
|
|
||||||
|
return debouncedValue
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Custom hook for throttling function calls
|
||||||
|
*
|
||||||
|
* @param callback - The function to throttle
|
||||||
|
* @param delay - The delay in milliseconds
|
||||||
|
* @returns The throttled function
|
||||||
|
*/
|
||||||
|
export function useThrottle<T extends (...args: any[]) => any>(
|
||||||
|
callback: T,
|
||||||
|
delay: number
|
||||||
|
): T {
|
||||||
|
const [lastCall, setLastCall] = useState<number>(0)
|
||||||
|
|
||||||
|
const throttledCallback = ((...args: Parameters<T>) => {
|
||||||
|
const now = Date.now()
|
||||||
|
if (now - lastCall >= delay) {
|
||||||
|
setLastCall(now)
|
||||||
|
return callback(...args)
|
||||||
|
}
|
||||||
|
}) as T
|
||||||
|
|
||||||
|
return throttledCallback
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Custom hook for preventing rapid state updates
|
||||||
|
*
|
||||||
|
* @param initialValue - Initial state value
|
||||||
|
* @param delay - Minimum delay between updates in milliseconds
|
||||||
|
* @returns [state, setState] tuple
|
||||||
|
*/
|
||||||
|
export function useThrottledState<T>(
|
||||||
|
initialValue: T,
|
||||||
|
delay: number = 100
|
||||||
|
): [T, (value: T) => void] {
|
||||||
|
const [state, setState] = useState<T>(initialValue)
|
||||||
|
const [lastUpdate, setLastUpdate] = useState<number>(0)
|
||||||
|
|
||||||
|
const setThrottledState = (value: T) => {
|
||||||
|
const now = Date.now()
|
||||||
|
if (now - lastUpdate >= delay) {
|
||||||
|
setState(value)
|
||||||
|
setLastUpdate(now)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return [state, setThrottledState]
|
||||||
|
}
|
||||||
|
|
@ -90,6 +90,15 @@ export const useAIVideoStore = create<AIVideoState>((set, get) => ({
|
||||||
},
|
},
|
||||||
|
|
||||||
updateJob: (jobId, updates) => {
|
updateJob: (jobId, updates) => {
|
||||||
|
// Throttle rapid updates to prevent excessive re-renders
|
||||||
|
const now = Date.now()
|
||||||
|
const lastUpdate = get().jobs.find(job => job.id === jobId)?.endTime || 0
|
||||||
|
|
||||||
|
if (now - lastUpdate < 100 && updates.progress !== undefined) {
|
||||||
|
// Skip rapid progress updates
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
set(state => ({
|
set(state => ({
|
||||||
jobs: state.jobs.map(job =>
|
jobs: state.jobs.map(job =>
|
||||||
job.id === jobId ? { ...job, ...updates } : job
|
job.id === jobId ? { ...job, ...updates } : job
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue