Skip to content

Commit 889a8d9

Browse files
committed
[REWORK] useEffectOne and useMergedRef
1 parent 81e0045 commit 889a8d9

4 files changed

Lines changed: 34 additions & 7 deletions

File tree

apps/react-tools-demo/src/components/hooks/useMergedRef/UseMergedRef.tsx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ export const UseMergedRef = () => {
1616
const mergedRef = useMergedRef<HTMLDivElement>(ref, refCb);
1717

1818
const changeBorderColor = () => {
19+
mergedRef.current;
1920
ref.current && (ref.current.style.border = ref.current.style.border.indexOf("lightgray") !== -1
2021
? '1px solid darkcyan'
2122
: '1px solid lightgray'

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -37,12 +37,12 @@ export const UseMergedRef = () => {
3737
## API
3838

3939
```tsx
40-
useMergedRef <T>(...refs: (React.Ref<T>)[])
40+
useMergedRef <T>(...refs: React.Ref<T>[])
4141
```
4242

4343
> ### Params
4444
>
45-
> - __refs__: _React.MutableRefObject<T>[]_
45+
> - __refs__: _React.Ref<T>[]_
4646
>
4747
4848
> ### Returns

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

Lines changed: 27 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,33 @@
11
import { EffectCallback, useEffect, useRef } from "react";
2-
import { useRerender } from "."
32

43
/**
54
* **`useEffectOnce`**: Hook to executes _effect_ and _clean up_ after component mount __only once__. It prevents _React 18 StrictMode_ behavior if present, otherwise it works like a normal _useEffect_ with empty dependencies array. __*N.B.*__ Not use in a component with normal _useEffect_, if it executes a _React.DispatchAction_, because this action is executes twice if there is _React.StrictMode_.
65
* @param {EffectCallback} effect
76
*/
7+
export const useEffectOnce = (effect: EffectCallback) => {
8+
const effectCalled = useRef(false);
9+
const cleanUpFn = useRef<ReturnType<EffectCallback>>();
10+
const rendered = useRef(false);
11+
useEffect(() => {
12+
if (!effectCalled.current) {
13+
cleanUpFn.current = effect();
14+
effectCalled.current = true;
15+
setTimeout(() => rendered.current = true, 1);
16+
}
17+
return () => {
18+
if (rendered.current) {
19+
cleanUpFn.current && cleanUpFn.current();
20+
effectCalled.current = false;
21+
}
22+
}
23+
// eslint-disable-next-line react-hooks/exhaustive-deps
24+
}, [])
25+
}
26+
27+
/**
28+
*
29+
* INFO this implementation works but gives a rerender.
30+
831
export const useEffectOnce = (effect: EffectCallback) => {
932
const update = useRerender();
1033
const effectFn = useRef(effect);
@@ -30,4 +53,6 @@ export const useEffectOnce = (effect: EffectCallback) => {
3053
}
3154
// eslint-disable-next-line react-hooks/exhaustive-deps
3255
}, []);
33-
}
56+
}
57+
58+
*/
Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import React, { MutableRefObject, useRef } from "react";
1+
import React, { MutableRefObject, useEffect, useRef } from "react";
22

33
/**
44
* **`useMergedRef`**: Hook to merge multiple refs into one.
@@ -7,7 +7,8 @@ import React, { MutableRefObject, useRef } from "react";
77
*/
88
export const useMergedRef = <T>(...refs: React.Ref<T>[]) => {
99
const mergedRef = useRef<T>(null);
10-
refs.forEach(ref => typeof ref === "function" ? ref(mergedRef.current) : (ref as MutableRefObject<T|null>).current = mergedRef.current);
11-
10+
useEffect(() => {
11+
refs.forEach(ref => typeof ref === "function" ? ref(mergedRef.current) : (ref as MutableRefObject<T | null>).current = mergedRef.current);
12+
}, [mergedRef.current]);
1213
return mergedRef;
1314
}

0 commit comments

Comments
 (0)