-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[feat]:
useMin
and useMax
renewed and organized
- Loading branch information
1 parent
6237291
commit 67ad9fe
Showing
16 changed files
with
288 additions
and
28 deletions.
There are no files selected for viewing
Empty file.
Empty file.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,67 @@ | ||
import { renderHook } from '@testing-library/react'; | ||
import { useMax } from '../useMax'; | ||
|
||
describe('useMax', () => { | ||
it('should return the maximum value from an array', () => { | ||
const { result } = renderHook(() => useMax([1, 2, 3, 4])); | ||
expect(result.current).toBe(4); | ||
}); | ||
|
||
it('should return the maximum value from multiple arguments', () => { | ||
const { result } = renderHook(() => useMax(1, 3, 2)); | ||
expect(result.current).toBe(3); | ||
}); | ||
|
||
it('should handle an empty array', () => { | ||
const { result } = renderHook(() => useMax([])); | ||
expect(result.current).toBe(-Infinity); | ||
}); | ||
|
||
it('should handle no arguments', () => { | ||
const { result } = renderHook(() => useMax()); | ||
expect(result.current).toBe(-Infinity); | ||
}); | ||
|
||
it('should handle a single argument', () => { | ||
const { result } = renderHook(() => useMax(5)); | ||
expect(result.current).toBe(5); | ||
}); | ||
|
||
it('should handle a mix of direct values and getter functions', () => { | ||
const value1 = 10; | ||
const value2 = () => 20; | ||
const value3 = () => 15; | ||
|
||
const { result } = renderHook(() => useMax(value1, value2, value3)); | ||
expect(result.current).toBe(20); | ||
}); | ||
|
||
it('should handle an array of direct values and getter functions', () => { | ||
const value1 = 10; | ||
const value2 = () => 20; | ||
const value3 = () => 15; | ||
|
||
const { result } = renderHook(() => useMax([value1, value2, value3])); | ||
expect(result.current).toBe(20); | ||
}); | ||
|
||
it('should memoize the result and only recompute when dependencies change', () => { | ||
const value1 = 10; | ||
const value2 = () => 20; | ||
|
||
const { result, rerender } = renderHook( | ||
({ value1, value2 }) => useMax(value1, value2), | ||
{ | ||
initialProps: { value1, value2 }, | ||
} | ||
); | ||
|
||
expect(result.current).toBe(20); | ||
|
||
rerender({ value1, value2 }); | ||
expect(result.current).toBe(20); | ||
|
||
rerender({ value1: 30, value2 }); | ||
expect(result.current).toBe(30); | ||
}); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
export * from './useMax'; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
{ | ||
"extends": "../../../tsconfig.json", | ||
"compilerOptions": { | ||
"baseUrl": "." | ||
}, | ||
"include": ["src", "index.ts"] | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
import { defineConfig } from 'tsup'; | ||
|
||
export default defineConfig({ | ||
clean: true, | ||
target: 'es2019', | ||
format: ['cjs', 'esm'], | ||
banner: { js: '"use client";' }, | ||
sourcemap: true, | ||
minify: false, | ||
outExtension({ format }) { | ||
return { | ||
js: `.${format}.js`, | ||
ts: `.${format}.ts`, | ||
}; | ||
}, | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,42 @@ | ||
import React from 'react'; | ||
import { useMax } from './useMax'; | ||
|
||
const UseMaxDemo = () => { | ||
const [num1, setNum1] = React.useState(5); | ||
const [num2, setNum2] = React.useState(10); | ||
const maxNum = useMax(num1, num2); | ||
|
||
return ( | ||
<div className="flex flex-col items-center justify-center h-screen"> | ||
<h1 className="text-4xl font-bold mb-4">useMax Demo</h1> | ||
<div className="flex items-center mb-4"> | ||
<label className="mr-2">Enter a number:</label> | ||
<input | ||
type="number" | ||
value={num1} | ||
onChange={e => setNum1(parseInt(e.target.value, 10))} | ||
max={10} | ||
min={-10} | ||
className="mr-2" | ||
/> | ||
<label>Maximum value:</label> | ||
<p className="text-2xl font-bold mb-4">{maxNum}</p> | ||
</div> | ||
<div className="flex items-center"> | ||
<label className="mr-2">Enter another number:</label> | ||
<input | ||
type="number" | ||
value={num2} | ||
onChange={e => setNum2(parseInt(e.target.value, 10))} | ||
max={10} | ||
min={-10} | ||
className="mr-2" | ||
/> | ||
<label>Maximum value:</label> | ||
<p className="text-2xl font-bold">{maxNum}</p> | ||
</div> | ||
</div> | ||
); | ||
}; | ||
|
||
export default UseMaxDemo; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,17 +1,32 @@ | ||
import { useCallback, useEffect, useState } from "react"; | ||
import { useMemo } from 'react'; | ||
|
||
type UpdateMaxFn = (newNumbers: number[]) => void; | ||
type ValueOrFunction<T> = T | (() => T); | ||
|
||
export const useMax = (numbers: number[]): [number, UpdateMaxFn] => { | ||
const [max, setMax] = useState<number>(() => Math.max(...numbers)); | ||
function resolveValue<T>(value: ValueOrFunction<T>): T { | ||
return typeof value === 'function' ? (value as Function)() : value; | ||
} | ||
|
||
const updateMax: UpdateMaxFn = useCallback((newNumbers: number[]) => { | ||
setMax(Math.max(...newNumbers)); | ||
}, []); | ||
|
||
useEffect(() => { | ||
updateMax(numbers); | ||
}, [numbers, updateMax]); | ||
|
||
return [max, updateMax]; | ||
}; | ||
/** | ||
* Returns the maximum value from the given arguments or array of values. | ||
* | ||
* @param {...any[]} args - The values or arrays of values to compare. | ||
* @returns {number} The maximum value among the given arguments or array of values. | ||
* | ||
* @example | ||
* const maxValue = useMax(1, 2, 3); | ||
* // maxValue is 3 | ||
* | ||
* @example | ||
* const maxValue = useMax([1, 2, 3]); | ||
* // maxValue is 3 | ||
*/ | ||
export function useMax(...args: any[]): number { | ||
return useMemo(() => { | ||
if (args.length === 1 && Array.isArray(resolveValue(args[0]))) { | ||
const array = resolveValue(args[0]) as ValueOrFunction<number>[]; | ||
return Math.max(...array.map(resolveValue)); | ||
} else { | ||
return Math.max(...args.map(resolveValue)); | ||
} | ||
}, args); | ||
} |
Empty file.
Empty file.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,32 @@ | ||
import { renderHook } from '@testing-library/react'; | ||
import { useMin } from '../useMin'; | ||
|
||
describe('useMin', () => { | ||
it('should return the minimum of a single array', () => { | ||
const { result } = renderHook(() => useMin([1, 2, 3, 4, -1, 10])); | ||
expect(result.current).toBe(-1); | ||
}); | ||
|
||
it('should return the minimum of multiple arguments', () => { | ||
const { result } = renderHook(() => useMin(5, 10, 15, -5, 0)); | ||
expect(result.current).toBe(-5); | ||
}); | ||
|
||
it('should handle references or functions inside an array', () => { | ||
const ref1 = 7; | ||
const ref2 = () => 3; | ||
const ref3 = 5; | ||
const { result } = renderHook(() => useMin([ref1, ref2, ref3])); | ||
expect(result.current).toBe(3); | ||
}); | ||
|
||
it('should return Infinity for an empty array', () => { | ||
const { result } = renderHook(() => useMin([])); | ||
expect(result.current).toBe(Infinity); | ||
}); | ||
|
||
it('should return Infinity for empty arguments', () => { | ||
const { result } = renderHook(() => useMin()); | ||
expect(result.current).toBe(Infinity); | ||
}); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
export * from './useMin'; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
{ | ||
"extends": "../../../tsconfig.json", | ||
"compilerOptions": { | ||
"baseUrl": "." | ||
}, | ||
"include": ["src", "index.ts"] | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
import { defineConfig } from 'tsup'; | ||
|
||
export default defineConfig({ | ||
clean: true, | ||
target: 'es2019', | ||
format: ['cjs', 'esm'], | ||
banner: { js: '"use client";' }, | ||
sourcemap: true, | ||
minify: false, | ||
outExtension({ format }) { | ||
return { | ||
js: `.${format}.js`, | ||
ts: `.${format}.ts`, | ||
}; | ||
}, | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,42 @@ | ||
import React from 'react'; | ||
import { useMin } from './useMin'; | ||
|
||
const UseMinDemo = () => { | ||
const [num1, setNum1] = React.useState(5); | ||
const [num2, setNum2] = React.useState(10); | ||
const minNum = useMin(num1, num2); | ||
|
||
return ( | ||
<div className="flex flex-col items-center justify-center h-screen"> | ||
<h1 className="text-4xl font-bold mb-4">useMin Demo</h1> | ||
<div className="flex items-center mb-4"> | ||
<label className="mr-2">Enter a number:</label> | ||
<input | ||
type="number" | ||
value={num1} | ||
onChange={e => setNum1(parseInt(e.target.value, 10))} | ||
max={10} | ||
min={-10} | ||
className="mr-2" | ||
/> | ||
<label>Minimum value:</label> | ||
<p className="text-2xl font-bold mb-4">{minNum}</p> | ||
</div> | ||
<div className="flex items-center"> | ||
<label className="mr-2">Enter another number:</label> | ||
<input | ||
type="number" | ||
value={num2} | ||
onChange={e => setNum2(parseInt(e.target.value, 10))} | ||
max={10} | ||
min={-10} | ||
className="mr-2" | ||
/> | ||
<label>Minimum value:</label> | ||
<p className="text-2xl font-bold">{minNum}</p> | ||
</div> | ||
</div> | ||
); | ||
}; | ||
|
||
export default UseMinDemo; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,19 +1,33 @@ | ||
import { useEffect, useRef, useState } from 'react' | ||
import { useMemo } from 'react'; | ||
|
||
type UpdateMinFn = (newNumbers: number[]) => void | ||
type ValueOrFunction<T> = T | (() => T); | ||
|
||
export const useMin = (numbers: number[]): [number, UpdateMinFn] => { | ||
const [min, setMin] = useState<number>(() => Math.min(...numbers)) | ||
const updateMinRef = useRef<UpdateMinFn>(() => {}) | ||
function resolveValue<T>(value: ValueOrFunction<T>): T { | ||
return typeof value === 'function' ? (value as Function)() : value; | ||
} | ||
|
||
useEffect(() => { | ||
const updateMin: UpdateMinFn = (newNumbers: number[]) => { | ||
setMin(Math.min(...newNumbers)) | ||
/** | ||
* Returns the minimum value from the given arguments. | ||
* | ||
* The `useMin` hook accepts any number of arguments, which can be either | ||
* individual values or arrays of values. If an array is provided, the hook | ||
* will return the minimum value from the array. If individual values are | ||
* provided, the hook will return the minimum value from those values. | ||
* | ||
* @param {...(number | (() => number) | number[])} args - The values or arrays of values from which to find the minimum. | ||
* @returns {number} The minimum value from the given arguments. | ||
* | ||
* @example | ||
* const minValue = useMin(1, 2, 3, 4, -1, 10); // Returns -1 | ||
* const minArrayValue = useMin([5, 10, 15, -5, 0]); // Returns -5 | ||
*/ | ||
export function useMin(...args: any[]): number { | ||
return useMemo(() => { | ||
if (args.length === 1 && Array.isArray(resolveValue(args[0]))) { | ||
const array = resolveValue(args[0]) as ValueOrFunction<number>[]; | ||
return Math.min(...array.map(resolveValue)); | ||
} else { | ||
return Math.min(...args.map(resolveValue)); | ||
} | ||
|
||
updateMin(numbers) | ||
updateMinRef.current = updateMin | ||
}, [numbers]) | ||
|
||
return [min, updateMinRef.current] | ||
}, args); | ||
} |