From 99a1882aad1923c25365546b09bfdad5b9cc2469 Mon Sep 17 00:00:00 2001 From: Julien Date: Thu, 13 Oct 2022 00:29:31 +0200 Subject: [PATCH] feat: create useToggle hook --- README.md | 2 + package-lock.json | 2 +- package.json | 2 +- src/index.ts | 2 + src/useBoolean/useBoolean.mdx | 4 ++ src/useCountdown/useCountdown.mdx | 1 + src/useToggle/useToggle.demo.tsx | 20 +++++++++ src/useToggle/useToggle.mdx | 10 +++++ src/useToggle/useToggle.test.ts | 59 ++++++++++++++++++++++++++ src/useToggle/useToggle.ts | 13 ++++++ templates/plop/hooks/hook/demo.tsx.hbs | 2 - templates/plop/hooks/hook/hook.ts.hbs | 2 - 12 files changed, 113 insertions(+), 6 deletions(-) create mode 100644 src/useToggle/useToggle.demo.tsx create mode 100644 src/useToggle/useToggle.mdx create mode 100644 src/useToggle/useToggle.test.ts create mode 100644 src/useToggle/useToggle.ts diff --git a/README.md b/README.md index 61486a16..7338c530 100644 --- a/README.md +++ b/README.md @@ -15,6 +15,7 @@ ![npm bundle size](https://img.shields.io/bundlephobia/minzip/usehooks-ts) ![npm](https://img.shields.io/npm/v/usehooks-ts) [![All Contributors](https://img.shields.io/badge/all_contributors-85-orange.svg?style=flat-square)](#contributors-) +
@@ -66,6 +67,7 @@ - [`useStep()`](https://usehooks-ts.com/react-hook/use-step) - [`useTernaryDarkMode()`](https://usehooks-ts.com/react-hook/use-ternary-dark-mode) - [`useTimeout()`](https://usehooks-ts.com/react-hook/use-timeout) +- [`useToggle()`](https://usehooks-ts.com/react-hook/use-toggle) - [`useUpdateEffect()`](https://usehooks-ts.com/react-hook/use-update-effect) - [`useWindowSize()`](https://usehooks-ts.com/react-hook/use-window-size) diff --git a/package-lock.json b/package-lock.json index 8252b386..a0e2f675 100644 --- a/package-lock.json +++ b/package-lock.json @@ -6,7 +6,7 @@ "packages": { "": { "name": "usehooks-ts", - "version": "2.7.0", + "version": "2.7.2", "license": "MIT", "workspaces": [ "packages/eslint-config-custom" diff --git a/package.json b/package.json index 209ec5d3..29352789 100644 --- a/package.json +++ b/package.json @@ -29,7 +29,7 @@ "test:watch": "npm run test -- --watch --silent", "test:coverage": "ts-node ./scripts/coverage.ts", "clean": "rimraf -rf ./dist", - "format": "prettier --check \"**/*.{json,md,mdx,css,scss,yaml,yml}\"", + "format": "prettier --write \"**/*.{json,md,mdx,css,scss,yaml,yml}\"", "lint": "eslint '**/*.{js,jsx,ts,tsx}'", "types-check": "tsc --noEmit", "bump": "bump --tag 'usehooks-ts@%s' --commit 'release: usehooks-ts@%s'", diff --git a/src/index.ts b/src/index.ts index b3479d56..d6d1fc11 100644 --- a/src/index.ts +++ b/src/index.ts @@ -66,6 +66,8 @@ export { default as useTernaryDarkMode } from './useTernaryDarkMode/useTernaryDa export * from './useTernaryDarkMode/useTernaryDarkMode' export { default as useTimeout } from './useTimeout/useTimeout' export * from './useTimeout/useTimeout' +export { default as useToggle } from './useToggle/useToggle' +export * from './useToggle/useToggle' export { default as useUpdateEffect } from './useUpdateEffect/useUpdateEffect' export * from './useUpdateEffect/useUpdateEffect' export { default as useWindowSize } from './useWindowSize/useWindowSize' diff --git a/src/useBoolean/useBoolean.mdx b/src/useBoolean/useBoolean.mdx index 2b1c512c..efa7ee69 100644 --- a/src/useBoolean/useBoolean.mdx +++ b/src/useBoolean/useBoolean.mdx @@ -4,3 +4,7 @@ date: '2021-07-29' --- A simple abstraction to play with a boolean, don't repeat yourself. + +Related hooks: + +- [`useToggle()`](/react-hook/use-toggle) diff --git a/src/useCountdown/useCountdown.mdx b/src/useCountdown/useCountdown.mdx index 2fe11ede..83aea243 100644 --- a/src/useCountdown/useCountdown.mdx +++ b/src/useCountdown/useCountdown.mdx @@ -12,5 +12,6 @@ NEW VERSION: A simple countdown implementation. Accepts `countStop`(new), `count Related hooks: - [`useBoolean()`](/react-hook/use-boolean) +- [`useToggle()`](/react-hook/use-toggle) - [`useCounter()`](/react-hook/use-counter) - [`useInterval()`](/react-hook/use-interval) diff --git a/src/useToggle/useToggle.demo.tsx b/src/useToggle/useToggle.demo.tsx new file mode 100644 index 00000000..cab24006 --- /dev/null +++ b/src/useToggle/useToggle.demo.tsx @@ -0,0 +1,20 @@ +import { useToggle } from '..' + +export default function Component() { + const [value, toggle, setValue] = useToggle() + + // Just an example to use "setValue" + const customToggle = () => setValue((x: boolean) => !x) + + return ( + <> +

+ Value is {value.toString()} +

+ + + + + + ) +} diff --git a/src/useToggle/useToggle.mdx b/src/useToggle/useToggle.mdx new file mode 100644 index 00000000..d6d6921f --- /dev/null +++ b/src/useToggle/useToggle.mdx @@ -0,0 +1,10 @@ +--- +title: useToggle +date: '2022-10-12' +--- + +A simple abstraction to play with a boolean, don't repeat yourself. + +Related hooks: + +- [`useBoolean()`](/react-hook/use-boolean) diff --git a/src/useToggle/useToggle.test.ts b/src/useToggle/useToggle.test.ts new file mode 100644 index 00000000..ceac4d4a --- /dev/null +++ b/src/useToggle/useToggle.test.ts @@ -0,0 +1,59 @@ +import { act, renderHook } from '@testing-library/react-hooks/dom' + +import useToggle from './useToggle' + +describe('use toggle()', () => { + test('should use toggle be ok', () => { + const { result } = renderHook(() => useToggle()) + const [value, toggle, setValue] = result.current + + expect(value).toBe(false) + expect(typeof toggle).toBe('function') + expect(typeof setValue).toBe('function') + }) + + test('should default value works', () => { + const { result } = renderHook(() => useToggle(true)) + const [value] = result.current + + expect(value).toBe(true) + }) + + test('setValue should mutate the value', () => { + const { result } = renderHook(() => useToggle()) + const [, , setValue] = result.current + + expect(result.current[0]).toBe(false) + + act(() => { + setValue(true) + }) + + expect(result.current[0]).toBe(true) + + act(() => { + setValue(prev => !prev) + }) + + expect(result.current[0]).toBe(false) + }) + + test('toggle should mutate the value', () => { + const { result } = renderHook(() => useToggle()) + const [, toggle] = result.current + + expect(result.current[0]).toBe(false) + + act(() => { + toggle() + }) + + expect(result.current[0]).toBe(true) + + act(() => { + toggle() + }) + + expect(result.current[0]).toBe(false) + }) +}) diff --git a/src/useToggle/useToggle.ts b/src/useToggle/useToggle.ts new file mode 100644 index 00000000..36962b99 --- /dev/null +++ b/src/useToggle/useToggle.ts @@ -0,0 +1,13 @@ +import { Dispatch, SetStateAction, useCallback, useState } from 'react' + +function useToggle( + defaultValue?: boolean, +): [boolean, () => void, Dispatch>] { + const [value, setValue] = useState(!!defaultValue) + + const toggle = useCallback(() => setValue(x => !x), []) + + return [value, toggle, setValue] +} + +export default useToggle diff --git a/templates/plop/hooks/hook/demo.tsx.hbs b/templates/plop/hooks/hook/demo.tsx.hbs index eb5bda66..b5f3cd04 100644 --- a/templates/plop/hooks/hook/demo.tsx.hbs +++ b/templates/plop/hooks/hook/demo.tsx.hbs @@ -1,5 +1,3 @@ -import React from 'react' - import { {{camelCase name}} } from '..' export default function Component() { diff --git a/templates/plop/hooks/hook/hook.ts.hbs b/templates/plop/hooks/hook/hook.ts.hbs index 936f02bc..151b80a6 100644 --- a/templates/plop/hooks/hook/hook.ts.hbs +++ b/templates/plop/hooks/hook/hook.ts.hbs @@ -1,5 +1,3 @@ -import {} from 'react' - function {{camelCase name}}(): [number, () => number] { const value = 2 const method = () => 2