Skip to content

Commit 912af7e

Browse files
authored
Fix render prop data in RadioGroup component (#1522)
* fix `slot` state of `RadioGroup` component The `useEvent` is 1 tick too late (due to the update of the callback happening in useEffect). This isn't a problem for event listeners, but it is for functions that need to run "now". We can change the `useLatestValue` hook to do something like: ```diff export function useLatestValue<T>(value: T) { let cache = useRef(value) - useIsoMorphicEffect(() => { - cache.current = value - }, [value]) + cache.current = value return cache } ``` But then we are mutating our refs in render which isn't ideal. * update changelog * add test to verify that the correct slot data is exposed
1 parent d19f797 commit 912af7e

File tree

3 files changed

+56
-6
lines changed

3 files changed

+56
-6
lines changed

packages/@headlessui-react/CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
1818
- Remove leftover code in Combobox component ([#1514](https://github.com/tailwindlabs/headlessui/pull/1514))
1919
- Fix event handlers with arity > 1 ([#1515](https://github.com/tailwindlabs/headlessui/pull/1515))
2020
- Fix transition `enter` bug ([#1519](https://github.com/tailwindlabs/headlessui/pull/1519))
21+
- Fix render prop data in `RadioGroup` component ([#1522](https://github.com/tailwindlabs/headlessui/pull/1522))
2122

2223
## [1.6.3] - 2022-05-25
2324

packages/@headlessui-react/src/components/radio-group/radio-group.test.tsx

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -322,6 +322,56 @@ describe('Rendering', () => {
322322
})
323323
)
324324

325+
it(
326+
'should expose internal data as a render prop',
327+
suppressConsoleLogs(async () => {
328+
function Example() {
329+
let [value, setValue] = useState(null)
330+
331+
return (
332+
<RadioGroup value={value} onChange={setValue}>
333+
<RadioGroup.Option value="a">Option 1</RadioGroup.Option>
334+
<RadioGroup.Option value="b">Option 2</RadioGroup.Option>
335+
<RadioGroup.Option value="c">Option 3</RadioGroup.Option>
336+
</RadioGroup>
337+
)
338+
}
339+
340+
render(<Example />)
341+
342+
let options = getRadioGroupOptions()
343+
344+
// Nothing is active yet
345+
expect(options[0]).toHaveAttribute('data-headlessui-state', '')
346+
expect(options[1]).toHaveAttribute('data-headlessui-state', '')
347+
expect(options[2]).toHaveAttribute('data-headlessui-state', '')
348+
349+
// Focus the RadioGroup
350+
await press(Keys.Tab)
351+
352+
// The first one should be active, but not checked yet
353+
expect(options[0]).toHaveAttribute('data-headlessui-state', 'active')
354+
expect(options[1]).toHaveAttribute('data-headlessui-state', '')
355+
expect(options[2]).toHaveAttribute('data-headlessui-state', '')
356+
357+
// Select the first one
358+
await press(Keys.Space)
359+
360+
// The first one should be active and checked
361+
expect(options[0]).toHaveAttribute('data-headlessui-state', 'checked active')
362+
expect(options[1]).toHaveAttribute('data-headlessui-state', '')
363+
expect(options[2]).toHaveAttribute('data-headlessui-state', '')
364+
365+
// Go to the next option
366+
await press(Keys.ArrowDown)
367+
368+
// The second one should be active and checked
369+
expect(options[0]).toHaveAttribute('data-headlessui-state', '')
370+
expect(options[1]).toHaveAttribute('data-headlessui-state', 'checked active')
371+
expect(options[2]).toHaveAttribute('data-headlessui-state', '')
372+
})
373+
)
374+
325375
describe('Equality', () => {
326376
let options = [
327377
{ id: 1, name: 'Alice' },
Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,12 @@
1-
import { useState } from 'react'
2-
import { useEvent } from './use-event'
1+
import { useState, useCallback } from 'react'
32

43
export function useFlags(initialFlags = 0) {
54
let [flags, setFlags] = useState(initialFlags)
65

7-
let addFlag = useEvent((flag: number) => setFlags((flags) => flags | flag))
8-
let hasFlag = useEvent((flag: number) => Boolean(flags & flag))
9-
let removeFlag = useEvent((flag: number) => setFlags((flags) => flags & ~flag))
10-
let toggleFlag = useEvent((flag: number) => setFlags((flags) => flags ^ flag))
6+
let addFlag = useCallback((flag: number) => setFlags((flags) => flags | flag), [flags])
7+
let hasFlag = useCallback((flag: number) => Boolean(flags & flag), [flags])
8+
let removeFlag = useCallback((flag: number) => setFlags((flags) => flags & ~flag), [setFlags])
9+
let toggleFlag = useCallback((flag: number) => setFlags((flags) => flags ^ flag), [setFlags])
1110

1211
return { addFlag, hasFlag, removeFlag, toggleFlag }
1312
}

0 commit comments

Comments
 (0)