Skip to content

Commit d0a2144

Browse files
committed
[ADD] useLazyRef hook
1 parent 78c684c commit d0a2144

8 files changed

Lines changed: 125 additions & 3 deletions

File tree

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
import { useRef } from "react";
2+
import { useInterval, useLazyRef, useRerender } from "../../../../../../packages/react-tools/src";
3+
4+
/**
5+
There are two functions __initializer__ and __initializerLazy__ that log a message when they runs then sum and return number from 0 to 100.
6+
7+
The component has:
8+
- a __lazyValue__ creates by _useLazyRef_ hook with __initializerLazy__ function as param.
9+
- a __value__ creates by _useRef_ hook with __initializer__ function executed as param.
10+
- a __rerender__ function created by _useRerender_ hook to force a rerender.
11+
- a __apply__ function created by _useInterval_ hook to execute __rerender__ function every second.
12+
- render a div with __lazyValue__ and __value__ values.
13+
14+
If you open devtools will see that __initializerLazy__ message is logged once while __initializer__ message every rerender.
15+
*/
16+
const initializer = () => {
17+
console.log("initializer run...")
18+
return Array(100).fill(true).reduce((prev, curr, index) => prev + index, 0);
19+
}
20+
21+
const initializerLazy = () => {
22+
console.log("initializerLazy run...")
23+
return Array(100).fill(true).reduce((prev, curr, index) => prev + index, 0);
24+
}
25+
26+
export const UseLazyRef = () => {
27+
const rerender = useRerender();
28+
const [apply] = useInterval(() => rerender(), 1000);
29+
const lazyValue = useLazyRef(initializerLazy);
30+
const value = useRef(initializer());
31+
32+
apply();
33+
34+
return (
35+
<div>
36+
<p>Value is: {value.current}</p>
37+
<p>LazyValue is: {lazyValue.current}</p>
38+
</div>
39+
);
40+
}

apps/react-tools-demo/src/constants/components.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ export const COMPONENTS = [
3737
"useMemoDeepCompare",
3838
"useCallbackCompare",
3939
"useCallbackDeepCompare",
40+
"useLazyRef"
4041
],
4142
//EVENTS
4243
[
Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
# useLazyRef
2+
Hook that works 'partially' like the _useState_ hook with lazy initialization: ensures that the __initializer__ function is executed only once.
3+
4+
## Usage
5+
6+
```tsx
7+
const initializer = () => {
8+
console.log("initializer run...")
9+
return Array(100).fill(true).reduce((prev, curr, index) => prev + index, 0);
10+
}
11+
12+
const initializerLazy = () => {
13+
console.log("initializerLazy run...")
14+
return Array(100).fill(true).reduce((prev, curr, index) => prev + index, 0);
15+
}
16+
17+
export const UseLazyRef = () => {
18+
const rerender = useRerender();
19+
const [apply] = useInterval(() => rerender(), 1000);
20+
const lazyValue = useLazyRef(initializerLazy);
21+
const value = useRef(initializer());
22+
23+
apply();
24+
25+
return (
26+
<div>
27+
<p>Value is: {value.current}</p>
28+
<p>LazyValue is: {lazyValue.current}</p>
29+
</div>
30+
);
31+
}
32+
```
33+
34+
> There are two functions __initializer__ and __initializerLazy__ that log a message when they runs then sum and return number from 0 to 100.
35+
>
36+
> The component has:
37+
> - a __lazyValue__ creates by _useLazyRef_ hook with __initializerLazy__ function as param.
38+
> - a __value__ creates by _useRef_ hook with __initializer__ function executed as param.
39+
> - a __rerender__ function created by _useRerender_ hook to force a rerender.
40+
> - a __apply__ function created by _useInterval_ hook to execute __rerender__ function every second.
41+
> - render a div with __lazyValue__ and __value__ values.
42+
>
43+
> If you open devtools will see that __initializerLazy__ message is logged once while __initializer__ message every rerender.
44+
45+
46+
## API
47+
48+
```tsx
49+
useLazyRef <T>(initializer: () => T): React.MutableRefObject<T>
50+
```
51+
52+
> ### Params
53+
>
54+
> - __initializer__: _()=>T_
55+
>
56+
57+
> ### Returns
58+
>
59+
>
60+
> - _React.MutableRefObject<T>_
61+
>

apps/react-tools-demo/src/markdown/useTitle.md

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,9 @@ export const UseTitle = () => {
2121
}
2222
```
2323

24-
> First, in a variable outside the component is kept track of the page title. The _useTitle_ hook is invoked in the component with the _title_ __Title 1__ parameter and the returned _setTitle_ function is used. After 3 seconds the title is changed with the _setTitle_ function to _title_ __Title 2__. When the component is unmounted, the title saved in the variable outside the component is set as the title.
24+
> First, in a variable outside the component is kept track of the page title. The _useTitle_ hook is invoked in the component with the _title_ __Title 1__ parameter and the returned _setTitle_ function is used. After 3 seconds the title is changed with the _setTitle_ function to _title_ __Title 2__.
25+
>
26+
> When the component is unmounted, the title saved in the variable outside the component is set as the title.
2527
2628

2729
## API

packages/react-tools/README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@
3535
- [x] useMemoizedFunction
3636
- [x] useMemoCompare
3737
- [x] useMemoDeepCompare
38+
- [x] useLazyRef
3839

3940
- __EVENTS__
4041
- [x] useEvents

packages/react-tools/src/hooks/index.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,4 +40,5 @@ export { useDocumentVisibility } from './useDocumentVisibility';
4040
export { useClipboard } from './useClipboard';
4141
export { useMediaQuery } from './useMediaQuery';
4242
export { useColorScheme } from './useColorScheme';
43-
export { useTitle } from './useTitle'
43+
export { useTitle } from './useTitle'
44+
export { useLazyRef } from './useLazyRef';
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
import { useRef } from "react"
2+
3+
const noValue = Symbol("useLazyRef.noValue");
4+
/**
5+
* **`useLazyRef`**: Hook that works 'partially' like the _useState_ hook with lazy initialization: ensures that the __initializer__ function is executed only once.
6+
* @param {()=>T} initializer
7+
* @returns {React.MutableRefObject<T>}
8+
*/
9+
export const useLazyRef = <T>(initializer: () => T): React.MutableRefObject<T> => {
10+
const ref = useRef<T | typeof noValue>(noValue);
11+
if (ref.current === noValue) {
12+
ref.current = initializer();
13+
}
14+
return ref as React.MutableRefObject<T>;
15+
}

packages/react-tools/src/index.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,8 @@ export {
4949
useClipboard,
5050
useMediaQuery,
5151
useColorScheme,
52-
useTitle
52+
useTitle,
53+
useLazyRef
5354
} from './hooks'
5455

5556
export {

0 commit comments

Comments
 (0)