Skip to content

Commit 5f95dd0

Browse files
jquensekyletsang
andauthored
feat(useToggleState): add useToggleState hook (#48)
* feat(useToggleState): add useToggleState hook * Apply suggestions from code review Co-authored-by: Kyle Tsang <6854874+kyletsang@users.noreply.github.com> Co-authored-by: Kyle Tsang <6854874+kyletsang@users.noreply.github.com>
1 parent a8f2acc commit 5f95dd0

File tree

2 files changed

+62
-0
lines changed

2 files changed

+62
-0
lines changed

src/useToggleState.ts

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
import { useReducer, Reducer } from 'react'
2+
3+
/**
4+
* Create a state setter pair for a boolean value that can be "switched".
5+
* Unlike `useState(false)`, `useToggleState` will automatically flip the state
6+
* value when its setter is called with no argument.
7+
*
8+
* @param initialState The initial boolean value
9+
* @returns A tuple of the current state and a setter
10+
*
11+
* ```jsx
12+
* const [show, toggleShow] = useToggleState(false)
13+
*
14+
* return (
15+
* <>
16+
* <button onClick={() => toggleShow()}>
17+
* Toggle
18+
* <button>
19+
*
20+
* {show && <strong>Now you can see me</strong>}
21+
* </>
22+
* )
23+
*
24+
* ```
25+
*/
26+
export default function useToggleState(initialState: boolean = false) {
27+
return useReducer<Reducer<boolean, boolean | undefined>>(
28+
(state: boolean, action?: boolean) => (action == null ? !state : action),
29+
initialState,
30+
) as [boolean, (value?: boolean) => void]
31+
}

test/useToggleState.test.tsx

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
import React from 'react'
2+
import { mount } from 'enzyme'
3+
import { act } from 'react-dom/test-utils'
4+
import useToggleState from '../src/useToggleState'
5+
6+
describe('useToggleState', () => {
7+
it('should toggle', () => {
8+
let toggleState: ReturnType<typeof useToggleState>
9+
10+
function Wrapper({ initial }: { initial?: boolean }) {
11+
toggleState = useToggleState(initial)
12+
return <span />
13+
}
14+
15+
const wrapper = mount(<Wrapper />)
16+
17+
expect(toggleState![0]).toEqual(false)
18+
19+
act(() => toggleState[1]())
20+
21+
expect(toggleState![0]).toEqual(true)
22+
23+
act(() => toggleState[1](true))
24+
25+
expect(toggleState![0]).toEqual(true)
26+
27+
act(() => toggleState[1]())
28+
29+
expect(toggleState![0]).toEqual(false)
30+
})
31+
})

0 commit comments

Comments
 (0)