diff --git a/CHANGELOG.md b/CHANGELOG.md index 9f571110..c03ab8b3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1008,3 +1008,9 @@ Errored release - Updates dependencies - Improves documentation - Improves types + +## [4.0.0] - 2023-03-13 + +### Adds + +- `useMutableState` hook diff --git a/README.md b/README.md index bd70f93b..cef4fdd9 100644 --- a/README.md +++ b/README.md @@ -85,10 +85,7 @@ import useSomeHook from 'beautiful-react-hooks/useSomeHook' ## 🎨 Hooks -* [useQueryParam](docs/useQueryParam.md) -* [useQueryParams](docs/useQueryParams.md) -* [useSearchQuery](docs/useSearchQuery.md) -* [useURLSearchParams](docs/useURLSearchParams.md) +* [useMutableState](docs/useMutableState.md) * [useInfiniteScroll](docs/useInfiniteScroll.md) * [useObservable](docs/useObservable.md) * [useEvent](docs/useEvent.md) @@ -130,6 +127,11 @@ import useSomeHook from 'beautiful-react-hooks/useSomeHook' * [useAudio](docs/useAudio.md) * [useObjectState](docs/useObjectState.md) * [useToggle](docs/useToggle.md) +* [useQueryParam](docs/useQueryParam.md) +* [useQueryParams](docs/useQueryParams.md) +* [useSearchQuery](docs/useSearchQuery.md) +* [useURLSearchParams](docs/useURLSearchParams.md) +*

diff --git a/docs/README.es-ES.md b/docs/README.es-ES.md index 3de5c7a2..8c7812df 100644 --- a/docs/README.es-ES.md +++ b/docs/README.es-ES.md @@ -76,10 +76,8 @@ $ yarn add beautiful-react-hooks ## 🎨 Hooks -* [useQueryParam](useQueryParam.md) -* [useQueryParams](useQueryParams.md) -* [useSearchQuery](useSearchQuery.md) -* [useInfiniteScroll](useInfiniteScroll.``md) +* [useMutableState](useMutableState.md) +* [useInfiniteScroll](useInfiniteScroll.md) * [useObservable](useObservable.md) * [useEvent](useEvent.md) * [useGlobalEvent](useGlobalEvent.md) @@ -119,6 +117,10 @@ $ yarn add beautiful-react-hooks * [useAudio](useAudio.md) * [useObjectState](useObjectState.md) * [useToggle](useToggle.md) +* [useQueryParam](useQueryParam.md) +* [useQueryParams](useQueryParams.md) +* [useSearchQuery](useSearchQuery.md) +* [useURLSearchParams](useURLSearchParams.md)

diff --git a/docs/README.it-IT.md b/docs/README.it-IT.md index 606db259..51a08886 100644 --- a/docs/README.it-IT.md +++ b/docs/README.it-IT.md @@ -75,10 +75,7 @@ $ yarn add beautiful-react-hooks ## 🎨 Hooks -* [useQueryParam](useQueryParam.md) -* [useQueryParams](useQueryParams.md) -* [useSearchQuery](useSearchQuery.md) -* [useURLSearchParams](useURLSearchParams.md) +* [useMutableState](useMutableState.md) * [useInfiniteScroll](useInfiniteScroll.md) * [useObservable](useObservable.md) * [useEvent](useEvent.md) @@ -119,6 +116,10 @@ $ yarn add beautiful-react-hooks * [useAudio](useAudio.md) * [useObjectState](useObjectState.md) * [useToggle](useToggle.md) +* [useQueryParam](useQueryParam.md) +* [useQueryParams](useQueryParams.md) +* [useSearchQuery](useSearchQuery.md) +* [useURLSearchParams](useURLSearchParams.md)

diff --git a/docs/README.jp-JP.md b/docs/README.jp-JP.md index deed31cf..d4f804fb 100644 --- a/docs/README.jp-JP.md +++ b/docs/README.jp-JP.md @@ -41,8 +41,7 @@ React のカスタムフックは抽象的なコンポーネントのビジネ これまでのところ、私たちが作成し、内部で共有されているフックの大半はかなりの頻度でコールバック参照、イベントとコンポーネントのライフサイクルに関して類似する点がある事が分かっています。
この理由から、私たちはそれらの知見を企業や専門家が開発プロセスをスピードアップするのに役立つ(*できれば*)便利な React フックのコレクションとして `beautiful-react-hooks` にまとめました。

-さらに、コードの読みやすさを考慮して、簡潔かつ具体的な API を作成しました。 -より大きなチームで使用し、共有できるように、学習曲線を可能な限り低く抑える事が可能です。 +さらに、コードの読みやすさを考慮して、簡潔かつ具体的な API を作成しました。 より大きなチームで使用し、共有できるように、学習曲線を可能な限り低く抑える事が可能です。 **-- フックを利用する前に、ドキュメントを確認して下さい! --** @@ -76,10 +75,7 @@ $ yarn add beautiful-react-hooks ## 🎨 Hooks -* [useQueryParam](useQueryParam.md) -* [useQueryParams](useQueryParams.md) -* [useSearchQuery](useSearchQuery.md) -* [useURLSearchParams](useURLSearchParams.md) +* [useMutableState](useMutableState.md) * [useInfiniteScroll](useInfiniteScroll.md) * [useObservable](useObservable.md) * [useEvent](useEvent.md) @@ -120,6 +116,10 @@ $ yarn add beautiful-react-hooks * [useAudio](useAudio.md) * [useObjectState](useObjectState.md) * [useToggle](useToggle.md) +* [useQueryParam](useQueryParam.md) +* [useQueryParams](useQueryParams.md) +* [useSearchQuery](useSearchQuery.md) +* [useURLSearchParams](useURLSearchParams.md)

@@ -131,7 +131,8 @@ $ yarn add beautiful-react-hooks ## Peer dependencies -いくつかのフックはサードパーティライブラリ(rxjs、react-router-dom、redux)の上に構築されているため、それらのライブラリが peer dependencies としてリストされていることに気づくかもしれません。直接的にそれらのフックを使用しない限り、依存関係としてインストールする必要はありません。 +いくつかのフックはサードパーティライブラリ(rxjs、react-router-dom、redux)の上に構築されているため、それらのライブラリが peer dependencies +としてリストされていることに気づくかもしれません。直接的にそれらのフックを使用しない限り、依存関係としてインストールする必要はありません。 ## コントリビューション @@ -143,7 +144,7 @@ $ yarn add beautiful-react-hooks 1. コードのテストを必ず書くようにし、PR を送る前に `npm test` と `npm build` を実行して問題がない事を確認してください。 2. カスタムフックを作成する場合には、ドキュメントに必ず追加するようにしてください。 - (*カスタムフックのドキュメントテンプレートを用意しています [HOOK_DOCUMENTATION_TEMPLATE](../HOOK_DOCUMENTATION_TEMPLATE.md)*). + (*カスタムフックのドキュメントテンプレートを用意しています [HOOK_DOCUMENTATION_TEMPLATE](../HOOK_DOCUMENTATION_TEMPLATE.md)*). ### 利用しているライブラリ diff --git a/docs/README.pl-PL.md b/docs/README.pl-PL.md index 01105a36..87f4a05b 100644 --- a/docs/README.pl-PL.md +++ b/docs/README.pl-PL.md @@ -77,10 +77,7 @@ $ yarn add beautiful-react-hooks ## 🎨 Hooki -* [useQueryParam](useQueryParam.md) -* [useQueryParams](useQueryParams.md) -* [useSearchQuery](useSearchQuery.md) -* [useURLSearchParams](useURLSearchParams.md) +* [useMutableState](useMutableState.md) * [useInfiniteScroll](useInfiniteScroll.md) * [useObservable](useObservable.md) * [useEvent](useEvent.md) @@ -121,6 +118,10 @@ $ yarn add beautiful-react-hooks * [useAudio](useAudio.md) * [useObjectState](useObjectState.md) * [useToggle](useToggle.md) +* [useQueryParam](useQueryParam.md) +* [useQueryParams](useQueryParams.md) +* [useSearchQuery](useSearchQuery.md) +* [useURLSearchParams](useURLSearchParams.md)

diff --git a/docs/README.pt-BR.md b/docs/README.pt-BR.md index 5772fe20..208bd5a5 100644 --- a/docs/README.pt-BR.md +++ b/docs/README.pt-BR.md @@ -76,10 +76,7 @@ $ yarn add beautiful-react-hooks ## 🎨 Hooks -* [useQueryParam](useQueryParam.md) -* [useQueryParams](useQueryParams.md) -* [useSearchQuery](useSearchQuery.md) -* [useURLSearchParams](useURLSearchParams.md) +* [useMutableState](useMutableState.md) * [useInfiniteScroll](useInfiniteScroll.md) * [useObservable](useObservable.md) * [useEvent](useEvent.md) @@ -120,6 +117,10 @@ $ yarn add beautiful-react-hooks * [useAudio](useAudio.md) * [useObjectState](useObjectState.md) * [useToggle](useToggle.md) +* [useQueryParam](useQueryParam.md) +* [useQueryParams](useQueryParams.md) +* [useSearchQuery](useSearchQuery.md) +* [useURLSearchParams](useURLSearchParams.md)

diff --git a/docs/README.uk-UA.md b/docs/README.uk-UA.md index 37088dcf..3a21b1f9 100644 --- a/docs/README.uk-UA.md +++ b/docs/README.uk-UA.md @@ -76,10 +76,7 @@ $ yarn add beautiful-react-hooks ## 🎨 Хуки -* [useQueryParam](useQueryParam.md) -* [useQueryParams](useQueryParams.md) -* [useSearchQuery](useSearchQuery.md) -* [useURLSearchParams](useURLSearchParams.md) +* [useMutableState](useMutableState.md) * [useInfiniteScroll](useInfiniteScroll.md) * [useObservable](useObservable.md) * [useEvent](useEvent.md) @@ -120,6 +117,10 @@ $ yarn add beautiful-react-hooks * [useAudio](useAudio.md) * [useObjectState](useObjectState.md) * [useToggle](useToggle.md) +* [useQueryParam](useQueryParam.md) +* [useQueryParams](useQueryParams.md) +* [useSearchQuery](useSearchQuery.md) +* [useURLSearchParams](useURLSearchParams.md)

diff --git a/docs/README.zh-CN.md b/docs/README.zh-CN.md index 65e8171b..7672e969 100644 --- a/docs/README.zh-CN.md +++ b/docs/README.zh-CN.md @@ -73,10 +73,7 @@ $ yarn add beautiful-react-hooks ## 🎨 Hooks -* [useQueryParam](useQueryParam.md) -* [useQueryParams](useQueryParams.md) -* [useSearchQuery](useSearchQuery.md) -* [useURLSearchParams](useURLSearchParams.md) +* [useMutableState](useMutableState.md) * [useInfiniteScroll](useInfiniteScroll.md) * [useObservable](useObservable.md) * [useEvent](useEvent.md) @@ -117,6 +114,10 @@ $ yarn add beautiful-react-hooks * [useAudio](useAudio.md) * [useObjectState](useObjectState.md) * [useToggle](useToggle.md) +* [useQueryParam](useQueryParam.md) +* [useQueryParams](useQueryParams.md) +* [useSearchQuery](useSearchQuery.md) +* [useURLSearchParams](useURLSearchParams.md)

diff --git a/docs/useMutableState.md b/docs/useMutableState.md new file mode 100644 index 00000000..14878e2b --- /dev/null +++ b/docs/useMutableState.md @@ -0,0 +1,35 @@ +# useMutableState + +This hook provides mutable states that trigger the component to re-render. It offers similar functionality to Svelte's reactivity, enabling +developers to write more efficient and concise code. + +### Why? 💡 + +- Improves code streamlining by providing a reactive state that can be used to trigger a rerender + +### Basic Usage: + +```jsx harmony +import { Typography, Space, Button, Tag } from 'antd'; +import useMutableState from 'beautiful-react-hooks/useMutableState'; + +const TestComponent = () => { + const counter = useMutableState({ value: 0 }); + + return ( + + + Counter: {counter.value} + + + + + + + ); +}; + + +``` + + diff --git a/package.json b/package.json index c0311545..91923e85 100644 --- a/package.json +++ b/package.json @@ -335,4 +335,4 @@ "require": "./useAudio.js" } } -} \ No newline at end of file +} diff --git a/src/useMutableState.ts b/src/useMutableState.ts new file mode 100644 index 00000000..20d701bc --- /dev/null +++ b/src/useMutableState.ts @@ -0,0 +1,22 @@ +import { useMemo, useState } from 'react' + +/** + * Returns a reactive value that can be used as a state. + */ +const useMutableState = >(initialState: TProxied) => { + if (typeof initialState !== 'object' || initialState === null) throw new Error('The initial state must be an object') + + const [, setState] = useState(0) + + return useMemo(() => new Proxy(initialState, { + set: (target, prop: keyof TProxied, value: TProxied[keyof TProxied]) => { + if (target && target[prop] !== value) { + target[prop] = value + setState((state) => (state + 1)) + } + return true + } + }), []) +} + +export default useMutableState diff --git a/test/useMutableState.spec.js b/test/useMutableState.spec.js new file mode 100644 index 00000000..19820b45 --- /dev/null +++ b/test/useMutableState.spec.js @@ -0,0 +1,37 @@ +import React, { useEffect } from 'react' +import { render } from '@testing-library/react' +import { cleanup, renderHook } from '@testing-library/react-hooks' +import useMutableState from '../dist/useMutableState' +import assertHook from './utils/assertHook' + +describe('useMutableState', () => { + beforeEach(cleanup) + + assertHook(useMutableState) + + it('should return an object', () => { + const { result } = renderHook(() => useMutableState({ value: 0 })) + + expect(result.current).to.be.an('object').that.has.property('value') + }) + + it('should re-render when the value changes', () => { + const spy = sinon.spy() + + const TestComponent = () => { + const state = useMutableState({ value: 0 }) + + spy() + + useEffect(() => { + state.value = 1 + }, []) + + return

val: {state.value}
+ } + + render() + + expect(spy.callCount).to.equal(2) + }) +})