Skip to content

Commit 95b94b0

Browse files
authored
Fix null switch bug (#194)
* Fix null enter bug * Fix listener remaining after dismount * Prevent React warning when boolean value is null
1 parent 49ae597 commit 95b94b0

File tree

2 files changed

+32
-12
lines changed

2 files changed

+32
-12
lines changed

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1216,6 +1216,7 @@ This component is heavily inspired by [react-json-view](https://github.com/mac-s
12161216
12171217
## Changelog
12181218
1219+
- **1.26.1**: Fix bug when submitting with keyboard after switching to `null` type ([#194](https://github.com/CarlosNZ/json-edit-react/pull/194))
12191220
- **1.26.0**:
12201221
- Handle non-standard data types (e.g. `undefined`, `BigInt`) when stringifying/parsing JSON
12211222
- More custom components (See [library ReadMe](https://github.com/CarlosNZ/json-edit-react/blob/main/custom-component-library/README.md))

src/ValueNodes.tsx

Lines changed: 31 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -256,6 +256,8 @@ export const BooleanValue: React.FC<InputProps & { value: boolean }> = ({
256256
}) => {
257257
const { getStyles } = useTheme()
258258

259+
if (typeof value !== 'boolean') return null
260+
259261
return isEditing ? (
260262
<input
261263
className="jer-input-boolean"
@@ -286,27 +288,44 @@ export const BooleanValue: React.FC<InputProps & { value: boolean }> = ({
286288
)
287289
}
288290

289-
// A custom hook to add a keyboard listener to a component that does't have
291+
// A custom hook to add a keyboard listener to a component that doesn't have
290292
// standard DOM keyboard behaviour (like inputs). Only used for the `null`
291293
// component here, but is exported for re-use with Custom Components if required
292294
export const useKeyboardListener = (isEditing: boolean, listener: (e: unknown) => void) => {
293295
const timer = useRef<number | undefined>(undefined)
296+
const currentListener = useRef(listener)
294297

298+
// Always update the ref to point to the latest listener
295299
useEffect(() => {
296-
if (!isEditing) {
297-
// The listener messes with other elements when switching rapidly (e.g.
298-
// when "getNext" is called repeatedly on inaccessible elements), so we
299-
// cancel the listener load before it even happens if this node gets
300-
// switched from isEditing to not in less than 100ms
301-
window.clearTimeout(timer.current)
302-
return
303-
}
300+
currentListener.current = listener
301+
}, [listener])
302+
303+
// Define our stable event handler function
304+
const eventHandler = (e: unknown) => {
305+
currentListener.current(e)
306+
}
307+
308+
useEffect(() => {
309+
// The listener messes with other elements when switching rapidly (e.g. when
310+
// "getNext" is called repeatedly on inaccessible elements), so we cancel
311+
// the listener load before it even happens if this node gets switched from
312+
// isEditing to not in less than 100ms
313+
window.clearTimeout(timer.current)
314+
315+
if (!isEditing) return
316+
304317
// Small delay to prevent registering keyboard input from previous element
305318
// if switched using "Tab"
306-
timer.current = window.setTimeout(() => window.addEventListener('keydown', listener), 100)
319+
timer.current = window.setTimeout(() => {
320+
window.addEventListener('keydown', eventHandler)
321+
}, 100)
307322

308-
return () => window.removeEventListener('keydown', listener)
309-
}, [isEditing, listener])
323+
// Cleanup function
324+
return () => {
325+
window.clearTimeout(timer.current)
326+
window.removeEventListener('keydown', eventHandler)
327+
}
328+
}, [isEditing])
310329
}
311330

312331
export const NullValue: React.FC<InputProps> = ({

0 commit comments

Comments
 (0)