diff --git a/CHANGELOG.md b/CHANGELOG.md index 5dbf8ebe..14d9beac 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -627,3 +627,10 @@ online ### Fixed - Webpack 5 error with the `isDevelopment` constant + + +## [0.31.0] - 2020-10-09 + +### Added + +- `useRenderInfo` hook and tests diff --git a/README.md b/README.md index 6d98ee9a..0db91bf7 100644 --- a/README.md +++ b/README.md @@ -100,6 +100,7 @@ $ yarn add beautiful-react-hooks * [useSessionStorage](docs/useSessionStorage.md) * [useStorage](docs/useStorage.md) * [useDefaultedState](docs/useDefaultedState.md) +* [useRenderInfo](docs/useRenderInfo.md)

diff --git a/docs/README.es-ES.md b/docs/README.es-ES.md index 04fd0c3b..35b88233 100644 --- a/docs/README.es-ES.md +++ b/docs/README.es-ES.md @@ -98,6 +98,7 @@ $ yarn add beautiful-react-hooks * [useSessionStorage](./useSessionStorage.md) * [useStorage](./useStorage.md) * [useDefaultedState](./useDefaultedState.md) +* [useRenderInfo](docs/useRenderInfo.md)

diff --git a/docs/README.it-IT.md b/docs/README.it-IT.md index 5f27befb..99b7e1e5 100644 --- a/docs/README.it-IT.md +++ b/docs/README.it-IT.md @@ -96,6 +96,8 @@ $ yarn add beautiful-react-hooks * [useSessionStorage](./useSessionStorage.md) * [useStorage](./useStorage.md) * [useDefaultedState](./useDefaultedState.md) +* [useRenderInfo](docs/useRenderInfo.md) +

diff --git a/docs/README.jp-JP.md b/docs/README.jp-JP.md index f82bd764..c51d542c 100644 --- a/docs/README.jp-JP.md +++ b/docs/README.jp-JP.md @@ -97,6 +97,7 @@ $ yarn add beautiful-react-hooks * [useSessionStorage](./useSessionStorage.md) * [useStorage](./useStorage.md) * [useDefaultedState](./useDefaultedState.md) +* [useRenderInfo](docs/useRenderInfo.md)

diff --git a/docs/README.pl-PL.md b/docs/README.pl-PL.md index 992851c9..526d7b88 100644 --- a/docs/README.pl-PL.md +++ b/docs/README.pl-PL.md @@ -96,6 +96,7 @@ $ yarn add beautiful-react-hooks * [useSessionStorage](./useSessionStorage.md) * [useStorage](./useStorage.md) * [useDefaultedState](./useDefaultedState.md) +* [useRenderInfo](docs/useRenderInfo.md)

diff --git a/docs/README.pt-BR.md b/docs/README.pt-BR.md index 7a72c249..095ee98b 100644 --- a/docs/README.pt-BR.md +++ b/docs/README.pt-BR.md @@ -97,6 +97,7 @@ $ yarn add beautiful-react-hooks * [useSessionStorage](./useSessionStorage.md) * [useStorage](./useStorage.md) * [useDefaultedState](./useDefaultedState.md) +* [useRenderInfo](docs/useRenderInfo.md)

diff --git a/docs/README.uk-UA.md b/docs/README.uk-UA.md index 5292734d..3daa1baa 100644 --- a/docs/README.uk-UA.md +++ b/docs/README.uk-UA.md @@ -98,6 +98,7 @@ $ yarn add beautiful-react-hooks * [useSessionStorage](./useSessionStorage.md) * [useStorage](./useStorage.md) * [useDefaultedState](./useDefaultedState.md) +* [useRenderInfo](docs/useRenderInfo.md)

diff --git a/docs/README.zh-CN.md b/docs/README.zh-CN.md index 4a137613..0d1b5306 100644 --- a/docs/README.zh-CN.md +++ b/docs/README.zh-CN.md @@ -96,6 +96,7 @@ $ yarn add beautiful-react-hooks * [useSessionStorage](./useSessionStorage.md) * [useStorage](./useStorage.md) * [useDefaultedState](./useDefaultedState.md) +* [useRenderInfo](docs/useRenderInfo.md)

diff --git a/docs/useRenderInfo.md b/docs/useRenderInfo.md new file mode 100644 index 00000000..d3dee6a3 --- /dev/null +++ b/docs/useRenderInfo.md @@ -0,0 +1,72 @@ +# useRenderInfo + +Takes a component name and prints information on how many time the component renders, at what time and how many seconds +has passed since the last render. + +### Why? 💡 + +- Easily display information on components render + +### Basic Usage: + +```jsx harmony +import useInterval from 'beautiful-react-hooks/useInterval'; +import useRenderInfo from 'beautiful-react-hooks/useRenderInfo'; + + +const RenderInfo = () => { + const [seconds, setSeconds] = React.useState(0); + + // repeat the function each 1000ms + useInterval(() => { + setSeconds(1 + seconds); + }, 1000); + + + useRenderInfo('Module'); + + return ( + +

Check the console!

+ + ); +}; + + +``` + +### Custom logs: + +```jsx harmony +import useInterval from 'beautiful-react-hooks/useInterval'; +import useRenderInfo from 'beautiful-react-hooks/useRenderInfo'; + + +const RenderInfo = () => { + const [seconds, setSeconds] = React.useState(0); + const info = useRenderInfo(); + + // repeat the function each 1000ms + useInterval(() => { + setSeconds(1 + seconds); + }, 1000); + + return ( + +

I'm not using the console, {info.sinceLast} seconds passed from the last render!

+
+ ); +}; + + +``` + +### Mastering the hook + +#### ✅ When to use + +- When debugging a component + +#### 🛑 What not to do + +- In production build, you don't want useless logs in console :) diff --git a/index.d.ts b/index.d.ts index e21b7318..388fecfd 100644 --- a/index.d.ts +++ b/index.d.ts @@ -16,8 +16,8 @@ type EventListenerOptions = { passive: boolean, } -type HandlerSetter > = (a: T) => void; - +type HandlerSetter> = (a: T) => void; + type Cancelable = { cancel(): void; flush(): void; @@ -268,3 +268,13 @@ type SpeechOptions = { } export declare const useSpeechSynthesis: (text: string, options?: SpeechOptions) => ({ speak: Function, speechSynthUtterance: SpeechSynthesisUtterance }); + + +type RenderInfo = { + module: string, + renders: number, + timestamp: number, + sinceLast: string, +} + +export declare const useRenderInfo: (name?: string, log?: boolean) => RenderInfo; diff --git a/package.json b/package.json index 0f19ea3d..dd6847b8 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "beautiful-react-hooks", - "version": "0.30.6", + "version": "0.31.0", "description": "A collection of beautiful (and hopefully useful) React hooks to speed-up your components and hooks development", "main": "index.js", "module": "esm/index.js", diff --git a/src/index.js b/src/index.js index 0f73c491..6ce0455a 100644 --- a/src/index.js +++ b/src/index.js @@ -33,3 +33,4 @@ export { default as useDefaultedState } from './useDefaultedState'; export { default as useObservable } from './useObservable'; export { default as useSpeechSynthesis } from './useSpeechSynthesis'; export { default as useSystemVoices } from './useSystemVoices'; +export { default as useRenderInfo } from './useRenderInfo'; diff --git a/src/useRenderInfo.js b/src/useRenderInfo.js new file mode 100644 index 00000000..895dd66c --- /dev/null +++ b/src/useRenderInfo.js @@ -0,0 +1,36 @@ +import { useRef } from 'react'; + +const getInitial = (module) => ({ + module, + renders: 0, + timestamp: null, + sinceLast: null, +}); + +/** + * useRenderInfo + * @param module + * @param log + * @returns {{renders: number, module: *, timestamp: null}} + */ +const useRenderInfo = (module = 'Unknown component', log = true) => { + const { current: info } = useRef(getInitial(module)); + const now = +Date.now(); + + info.renders += 1; + info.sinceLast = info.timestamp ? (now - info.timestamp) / 1000 : '[now]'; + info.timestamp = now; + + if (log) { + /* eslint-disable no-console */ + console.group(`${module} info`); + console.log(`Render no: ${info.renders}${info.renders > 1 ? `, ${info.sinceLast}s since last render` : ''}`); + console.dir(info); + console.groupEnd(); + /* eslint-enable no-console */ + } + + return info; +}; + +export default useRenderInfo; diff --git a/test/useRenderInfo.spec.js b/test/useRenderInfo.spec.js new file mode 100644 index 00000000..d8d03cc5 --- /dev/null +++ b/test/useRenderInfo.spec.js @@ -0,0 +1,45 @@ +import React from 'react'; +import { cleanup, renderHook } from '@testing-library/react-hooks'; +import useRenderInfo from '../dist/useRenderInfo'; + +describe('useRenderInfo', () => { + beforeEach(cleanup); + + afterEach(sinon.restore); + + it('should be a function', () => { + expect(useRenderInfo).to.be.a('function'); + }); + + it('should return an information object', () => { + const name = 'Foo'; + const { result: { current: info } } = renderHook(() => useRenderInfo(name, false)); + + expect(info).to.be.an('object'); + expect(info.module).to.equal(name); + expect(info.renders).to.be.a('number'); + expect(info.sinceLast).to.be.a('string'); + expect(info.timestamp).to.be.a('number'); + }); + + it('should print consistent information', () => { + const { result: { current: info }, rerender } = renderHook(() => useRenderInfo('foo', false)); + + rerender(); + rerender(); + + expect(info.renders).to.equal(3); + }); + + it('should print renders information in group', () => { + const groupSpy = sinon.spy(console, 'group'); + const groupEndSpy = sinon.spy(console, 'groupEnd'); + const logSpy = sinon.spy(console, 'log'); + + renderHook(() => useRenderInfo(name, true)); + + expect(logSpy.called).to.be.true; + expect(groupSpy.called).to.be.true; + expect(groupEndSpy.called).to.be.true; + }); +});