@@ -53,7 +53,9 @@ export function useDebugAssertConstant<T>(value: T) {
53
53
}
54
54
55
55
/**
56
- * True just when `value` has been true continuously for the past `duration`.
56
+ * True just when `value` has not changed for the past `duration`.
57
+ *
58
+ * "Changed" means last render's and this render's `value`s aren't ===.
57
59
*
58
60
* When the given time has elapsed so that this hook's return value becomes
59
61
* true, it causes a rerender through a state update.
@@ -66,28 +68,53 @@ export function useDebugAssertConstant<T>(value: T) {
66
68
* that in particular this hook gets called again) whenever `value` will
67
69
* have changed; for example, by using a prop or a `useState` value.
68
70
*/
69
- export const useHasStayedTrueForMs = ( value : boolean , duration : number ) : boolean => {
71
+ export const useHasNotChangedForMs = ( value : mixed , duration : number ) : boolean => {
70
72
useDebugAssertConstant ( duration ) ;
71
73
72
74
const [ result , setResult ] = useState ( false ) ;
73
75
74
76
useEffect ( ( ) => {
75
- if ( value ) {
76
- const id = setTimeout ( ( ) => setResult ( true ) , duration ) ;
77
- return ( ) => clearTimeout ( id ) ;
78
- } else {
79
- setResult ( false ) ;
80
- }
77
+ setResult ( false ) ;
78
+ const id = setTimeout ( ( ) => setResult ( true ) , duration ) ;
79
+ return ( ) => clearTimeout ( id ) ;
80
+ } , [
81
81
// If `duration` changes, we'll tear down the old timeout and start the
82
82
// timer over. That isn't really ideal behavior... but we don't
83
83
// actually have a use case for a dynamic `duration`, and supporting it
84
84
// properly would be more complex, so we've just forbidden that as part
85
85
// of this hook function's interface.
86
- } , [ value , duration ] ) ;
86
+ duration ,
87
+
88
+ // Otherwise, trigger the effect just if React sees a change in `value`.
89
+ // In other words, just when last render's and this render's `value`s
90
+ // aren't ===.
91
+ value ,
92
+ ] ) ;
87
93
88
94
return result ;
89
95
} ;
90
96
97
+ /**
98
+ * True just when `value` has been true continuously for the past `duration`.
99
+ *
100
+ * When the given time has elapsed so that this hook's return value becomes
101
+ * true, it causes a rerender through a state update.
102
+ *
103
+ * The caller must use a constant `duration` through the lifetime of a given
104
+ * component instance.
105
+ *
106
+ * Note this hook doesn't (and can't) do anything to cause a rerender when
107
+ * `value` changes. The caller must ensure that the component rerenders (so
108
+ * that in particular this hook gets called again) whenever `value` will
109
+ * have changed; for example, by using a prop or a `useState` value.
110
+ */
111
+ export const useHasStayedTrueForMs = ( value : boolean , duration : number ) : boolean => {
112
+ useDebugAssertConstant ( duration ) ;
113
+
114
+ const hasNotChangedForDuration = useHasNotChangedForMs ( value , duration ) ;
115
+ return value && hasNotChangedForDuration ;
116
+ } ;
117
+
91
118
/**
92
119
* Like `useEffect`, but the callback only runs when `value` is true.
93
120
*
0 commit comments