47 lines
1.4 KiB
TypeScript
47 lines
1.4 KiB
TypeScript
'use client'
|
||
import { useState, useRef } from 'react'
|
||
|
||
/**
|
||
* 脏状态追踪 Hook — 用于"修改后才显示保存按钮"模式。
|
||
*
|
||
* @example 数组场景(每个子项独立保存)
|
||
* const { isDirty, markClean, removeItem } = useDirtyTracker()
|
||
* {items.map(item => (
|
||
* <div key={item.id}>
|
||
* <input onChange={...} />
|
||
* {isDirty(item.id, item) && <button onClick={save}>保存</button>}
|
||
* </div>
|
||
* ))}
|
||
* // 保存成功后: markClean(id, savedItem)
|
||
* // 删除时: removeItem(id)
|
||
*/
|
||
export function useDirtyTracker() {
|
||
const savedMap = useRef<Map<string, string>>(new Map())
|
||
|
||
/**
|
||
* 判断指定 key 的当前数据是否相对于上次 markClean 有修改。
|
||
* 从未 markClean 过的 key 视为 dirty(适用于新增项)。
|
||
*/
|
||
const isDirty = (key: string, current: unknown): boolean => {
|
||
const saved = savedMap.current.get(key)
|
||
if (saved === undefined) return true // 从未保存过 → dirty
|
||
return saved !== JSON.stringify(current)
|
||
}
|
||
|
||
/**
|
||
* 将指定 key 的当前数据标记为"已保存"(重置 dirty 状态)。
|
||
*/
|
||
const markClean = (key: string, item: unknown): void => {
|
||
savedMap.current.set(key, JSON.stringify(item))
|
||
}
|
||
|
||
/**
|
||
* 删除指定 key 的追踪记录(用于列表项被删除时清理)。
|
||
*/
|
||
const removeItem = (key: string): void => {
|
||
savedMap.current.delete(key)
|
||
}
|
||
|
||
return { isDirty, markClean, removeItem }
|
||
}
|