Skip to content

Commit 81e0045

Browse files
committed
[IMPL] useMergedRef hook
1 parent 1eb46ff commit 81e0045

17 files changed

Lines changed: 183 additions & 16 deletions

apps/react-tools-demo/scripts/generateMarkdown.js

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,20 @@ function getIndexClosedBracketTypeParam(line) {
3131
return end;
3232
}
3333

34+
/**
35+
*
36+
* @param {string} string
37+
* @returns {number}
38+
*/
39+
function sanitizeType(string) {
40+
let stringVal = string;
41+
let arrowIndex = stringVal.indexOf("=>");
42+
while(arrowIndex !== -1) {
43+
stringVal = stringVal.substring(0, arrowIndex+1) + stringVal.substring(arrowIndex+2);
44+
arrowIndex = stringVal.indexOf("=>");
45+
}
46+
return stringVal.split(">").length;
47+
}
3448
/**
3549
*
3650
* @param {string} string
@@ -41,7 +55,7 @@ function splitType(string){
4155
let newCode = [];
4256
let last = "";
4357
for (let part of string){
44-
if (last.split("<").length === last.split(/[^=]>/).length && last.split("(").length === last.split(")").length && last.split("[").length === last.split("]").length && last.split("{").length === last.split("}").length){
58+
if (last.split("<").length === sanitizeType(last) && last.split("(").length === last.split(")").length && last.split("[").length === last.split("]").length && last.split("{").length === last.split("}").length){
4559
last = part;
4660
newCode.push(part);
4761
}
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
import { useRef, useState } from "react";
2+
import { useMergedRef, useResizeObserver } from "../../../../../../packages/react-tools/src";
3+
4+
/**
5+
The component has a ref to change border color of a div element when a button is clicked and use _useResizeObserver_ hook to observe the size of div element to check when its width is less of 100px. Since _useResizeObserver_ works with a ref attached to an element, there are two ref that will be attached to the div element. So it has been used _useMergedRef_ hook to merge refs.
6+
*/
7+
export const UseMergedRef = () => {
8+
const [state, setState] = useState(false);
9+
const [refCb] = useResizeObserver<HTMLDivElement>(
10+
(entries: ResizeObserverEntry[]) => {
11+
const result = entries[0].contentRect.width < 100;
12+
result !== state && setState(result);
13+
}
14+
);
15+
const ref = useRef<HTMLDivElement>(null);
16+
const mergedRef = useMergedRef<HTMLDivElement>(ref, refCb);
17+
18+
const changeBorderColor = () => {
19+
ref.current && (ref.current.style.border = ref.current.style.border.indexOf("lightgray") !== -1
20+
? '1px solid darkcyan'
21+
: '1px solid lightgray'
22+
);
23+
}
24+
25+
return <div>
26+
<p>{"Has width < 100 px: " + state}</p>
27+
<div ref={mergedRef} style={{border: '1px solid lightgray', width: 150, height: 200, resize: "both", overflow: 'auto'}}></div>
28+
<br />
29+
<button onClick={changeBorderColor}>Change border color</button>
30+
</div>
31+
}

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ export const COMPONENTS = [
3838
"useCallbackCompare",
3939
"useCallbackDeepCompare",
4040
"useLazyRef",
41+
"useMergedRef",
4142
"useId"
4243
],
4344
//EVENTS

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

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -80,8 +80,12 @@ object with serializer and deserializer function to handle values in localStorag
8080
> - _() => T_
8181
> - _() => void_
8282
> - __Array__:
83-
> - _Dispatch<SetStateAction<T>>, () => T, () => void_
83+
> - _Dispatch<SetStateAction<T>>_
84+
> - _() => T_
85+
> - _() => void_
8486
> - __Array__:
8587
> - _T_
86-
> - _Dispatch<SetStateAction<T>>, () => T, () => void_
88+
> - _Dispatch<SetStateAction<T>>_
89+
> - _() => T_
90+
> - _() => void_
8791
>
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
# useMergedRef
2+
Hook to merge multiple refs into one.
3+
4+
## Usage
5+
6+
```tsx
7+
export const UseMergedRef = () => {
8+
const [state, setState] = useState(false);
9+
const [refCb] = useResizeObserver<HTMLDivElement>(
10+
(entries: ResizeObserverEntry[]) => {
11+
const result = entries[0].contentRect.width < 100;
12+
result !== state && setState(result);
13+
}
14+
);
15+
const ref = useRef<HTMLDivElement>(null);
16+
const mergedRef = useMergedRef<HTMLDivElement>(ref, refCb);
17+
18+
const changeBorderColor = () => {
19+
ref.current && (ref.current.style.border = ref.current.style.border.indexOf("lightgray") !== -1
20+
? '1px solid darkcyan'
21+
: '1px solid lightgray'
22+
);
23+
}
24+
25+
return <div>
26+
<p>{"Has width < 100 px: " + state}</p>
27+
<div ref={mergedRef} style={{border: '1px solid lightgray', width: 150, height: 200, resize: "both", overflow: 'auto'}}></div>
28+
<br />
29+
<button onClick={changeBorderColor}>Change border color</button>
30+
</div>
31+
}
32+
```
33+
34+
> The component has a ref to change border color of a div element when a button is clicked and use _useResizeObserver_ hook to observe the size of div element to check when its width is less of 100px. Since _useResizeObserver_ works with a ref attached to an element, there are two ref that will be attached to the div element. So it has been used _useMergedRef_ hook to merge refs.
35+
36+
37+
## API
38+
39+
```tsx
40+
useMergedRef <T>(...refs: (React.Ref<T>)[])
41+
```
42+
43+
> ### Params
44+
>
45+
> - __refs__: _React.MutableRefObject<T>[]_
46+
>
47+
48+
> ### Returns
49+
>
50+
> __mergedRef__
51+
> - _React.RefObject<T>_
52+
>

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

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,5 +28,7 @@ Function that should return the _initial state_. If it’s not specified, the in
2828
> __array__
2929
> - __Array__:
3030
> - _ReducerState<R>_
31-
> - _Dispatch<ReducerAction<R>>, ()=>ReducerState<R>, ()=>void_
31+
> - _Dispatch<ReducerAction<R>>_
32+
> - _()=>ReducerState<R>_
33+
> - _()=>void_
3234
>

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

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,5 +30,15 @@ history capacity (default 'no-limit').
3030
> __array__
3131
> - __Array__:
3232
> - _ReducerState<R>_
33-
> - _Dispatch<ReducerAction<R>>, {history: readonly ReducerState<R>[], presentPointer: number, trackUpdate: (enable:boolean) => void, canUndo: boolean, canRedo: boolean, undo: () => void, redo: () => void, go: (index: number) => void, clear: (value?: ReducerAction<R>) => void}_
33+
> - _Dispatch<ReducerAction<R>>_
34+
> - __Object__:
35+
> - __history__ : _readonly ReducerState<R>[]_
36+
> - __presentPointer__ : _number_
37+
> - __trackUpdate__ : _(enable:boolean) => void_
38+
> - __canUndo__ : _boolean_
39+
> - __canRedo__ : _boolean_
40+
> - __undo__ : _() => void_
41+
> - __redo__ : _() => void_
42+
> - __go__ : _(index: number) => void_
43+
> - __clear__ : _(value?: ReducerAction<R>) => void_
3444
>

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

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,5 +30,16 @@ history capacity (default 'no-limit').
3030
> __array__
3131
> - __Array__:
3232
> - _ReducerState<R>_
33-
> - _Dispatch<ReducerAction<R>>, ()=>ReducerState<R>, {history: readonly ReducerState<R>[], presentPointer: number, trackUpdate: (enable:boolean) => void, canUndo: boolean, canRedo: boolean, undo: () => void, redo: () => void, go: (index: number) => void, clear: (value?: ReducerAction<R>) => void}_
33+
> - _Dispatch<ReducerAction<R>>_
34+
> - _()=>ReducerState<R>_
35+
> - __Object__:
36+
> - __history__ : _readonly ReducerState<R>[]_
37+
> - __presentPointer__ : _number_
38+
> - __trackUpdate__ : _(enable:boolean) => void_
39+
> - __canUndo__ : _boolean_
40+
> - __canRedo__ : _boolean_
41+
> - __undo__ : _() => void_
42+
> - __redo__ : _() => void_
43+
> - __go__ : _(index: number) => void_
44+
> - __clear__ : _(value?: ReducerAction<R>) => void_
3445
>

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,15 +5,15 @@ Hook to work with [Screen Orientation API](https://developer.mozilla.org/en-US/d
55

66
```tsx
77
export const UseScreen = () => {
8-
const [details] = useScreen();
8+
const [details] = useScreen(true);
99

1010
return <div style={{ textAlign: "left", padding: "0 1em", maxHeight: 300, overflow: "auto", border: "1px solid lightgray" }}>
1111
<p><strong>Current screen:</strong></p>
1212
<pre>{JSON.stringify(details.currentScreen, null, 2)}</pre>
1313
<p><strong>Screens:</strong></p>
1414
{
1515
details.screens?.map((el, index) => (
16-
<pre key={index}>{JSON.stringify(el, null, 2)}</pre>
16+
<pre key={index}>{el.label}</pre>
1717
))
1818
}
1919
</div>

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

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -83,8 +83,12 @@ object with serializer and deserializer function to handle values in sessionStor
8383
> - _() => T_
8484
> - _() => void_
8585
> - __Array__:
86-
> - _Dispatch<SetStateAction<T>>, () => T, () => void_
86+
> - _Dispatch<SetStateAction<T>>_
87+
> - _() => T_
88+
> - _() => void_
8789
> - __Array__:
8890
> - _T_
89-
> - _Dispatch<SetStateAction<T>>, () => T, () => void_
91+
> - _Dispatch<SetStateAction<T>>_
92+
> - _() => T_
93+
> - _() => void_
9094
>

0 commit comments

Comments
 (0)