Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
37 commits
Select commit Hold shift + click to select a range
5d3e2f3
chore: update eslint plugin react hooks
snowystinger Oct 10, 2025
7b96414
fix all lint errors
snowystinger Oct 10, 2025
7f79dd9
Add lines for other config items
snowystinger Oct 13, 2025
1208e74
Revert "fix all lint errors"
snowystinger Oct 13, 2025
3f9b6c9
fix all rules of hooks and exhaustive dependencies
snowystinger Oct 14, 2025
116fe27
enable all rules we are already passing
snowystinger Oct 14, 2025
a7d4e7e
fix event order and cleanup
snowystinger Oct 15, 2025
30bc1fa
fix lint
snowystinger Oct 15, 2025
5a45466
Merge branch 'main' into update-eslint-plugin-react-hooks
snowystinger Oct 15, 2025
ba77f40
turn on and fix static-components
snowystinger Oct 15, 2025
8f1cd8e
turn on and fix set-state-in-effect
snowystinger Oct 15, 2025
95687e9
turn on and fix purity
snowystinger Oct 15, 2025
a5803c0
fix lower react version tests
snowystinger Oct 15, 2025
be90742
turn on globals and fix errors
snowystinger Oct 15, 2025
90d350c
Turn on immutability and start trying to fix it
snowystinger Oct 15, 2025
8c6d21f
fix all the "easy" cases
snowystinger Oct 15, 2025
e7b7fea
feat: Support function setState callback in useControlledState
devongovett Oct 16, 2025
7057ed4
fixes
devongovett Oct 16, 2025
3a5e3b2
fix docs build
snowystinger Oct 16, 2025
c0dcf3f
fix useDateFieldState immutable lint errors
snowystinger Oct 16, 2025
a84fd47
fix as much immutability and eslint-disables as possible
snowystinger Oct 17, 2025
4cd669d
Merge branch 'main' into update-eslint-plugin-react-hooks
snowystinger Oct 17, 2025
c073772
Merge branch 'update-eslint-plugin-react-hooks' into update-eslint-pl…
snowystinger Oct 17, 2025
2d55869
Merge branch 'update-eslint-plugin-react-hooks-followup' into update-…
snowystinger Oct 17, 2025
bbd6a6f
fix docs
snowystinger Oct 17, 2025
2f591d5
move event listener attachment to an effect
snowystinger Oct 19, 2025
500c564
Merge branch 'update-eslint-plugin-react-hooks' into update-eslint-pl…
snowystinger Oct 19, 2025
a81fa41
convert remaining useElementTypes
snowystinger Oct 19, 2025
bad9964
Merge branch 'main' into update-eslint-plugin-react-hooks
snowystinger Oct 23, 2025
e88adfa
Merge branch 'update-eslint-plugin-react-hooks' into update-eslint-pl…
snowystinger Oct 23, 2025
b0cf01c
Merge branch 'update-eslint-plugin-react-hooks-followup' into update-…
snowystinger Oct 23, 2025
fe3d7b5
fix read from ref in render
snowystinger Oct 23, 2025
37dee08
Merge branch 'main' into update-eslint-plugin-react-hooks-followup
snowystinger Oct 24, 2025
785d9cd
Merge branch 'update-eslint-plugin-react-hooks-followup' into update-…
snowystinger Oct 24, 2025
094f8ea
fix docs
snowystinger Oct 27, 2025
b39c71e
Merge branch 'main' into update-eslint-plugin-react-hooks-immutability
snowystinger Nov 6, 2025
c424850
revert scrollview
snowystinger Nov 6, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 1 addition & 2 deletions eslint.config.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -235,7 +235,7 @@ export default [{
'react-hooks/component-hook-factories': ERROR,
'react-hooks/gating': ERROR,
'react-hooks/globals': ERROR,
// 'react-hooks/immutability': ERROR,
'react-hooks/immutability': ERROR,
// 'react-hooks/preserve-manual-memoization': ERROR, // No idea how to turn this one on yet
'react-hooks/purity': ERROR,
// 'react-hooks/refs': ERROR, // can't turn on until https://github.com/facebook/react/issues/34775 is fixed
Expand All @@ -250,7 +250,6 @@ export default [{
"rsp-rules/sort-imports": [ERROR],
"rulesdir/imports": [ERROR],
"rulesdir/useLayoutEffectRule": [ERROR],
"rulesdir/pure-render": [ERROR],
"jsx-a11y/accessible-emoji": ERROR,
"jsx-a11y/alt-text": ERROR,
"jsx-a11y/anchor-has-content": ERROR,
Expand Down
3 changes: 2 additions & 1 deletion packages/@react-aria/breadcrumbs/src/useBreadcrumbItem.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,8 @@ export function useBreadcrumbItem(props: AriaBreadcrumbItemProps, ref: RefObject
...otherProps
} = props;

let {linkProps} = useLink({isDisabled: isDisabled || isCurrent, elementType, ...otherProps}, ref);
let {linkProps: linkBaseLinkProps} = useLink({isDisabled: isDisabled || isCurrent, elementType, ...otherProps}, ref);
let linkProps = {...linkBaseLinkProps};
let isHeading = /^h[1-6]$/.test(elementType);
let itemProps: DOMAttributes = {};

Expand Down
3 changes: 2 additions & 1 deletion packages/@react-aria/button/src/useButton.ts
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,8 @@ export function useButton(props: AriaButtonOptions<ElementType>, ref: RefObject<
ref
});

let {focusableProps} = useFocusable(props, ref);
let {focusableProps: focusableBaseFocusableProps} = useFocusable(props, ref);
let focusableProps = {...focusableBaseFocusableProps};
if (allowFocusWhenDisabled) {
focusableProps.tabIndex = isDisabled ? -1 : focusableProps.tabIndex;
}
Expand Down
3 changes: 2 additions & 1 deletion packages/@react-aria/button/src/useToggleButtonGroup.ts
Original file line number Diff line number Diff line change
Expand Up @@ -77,11 +77,12 @@ export function useToggleButtonGroupItem(props: AriaToggleButtonGroupItemOptions
}
};

let {isPressed, isSelected, isDisabled, buttonProps} = useToggleButton({
let {isPressed, isSelected, isDisabled, buttonProps: toggleButtonProps} = useToggleButton({
...props,
id: undefined,
isDisabled: props.isDisabled || state.isDisabled
}, toggleState, ref);
let buttonProps = {...toggleButtonProps};
if (state.selectionMode === 'single') {
buttonProps.role = 'radio';
buttonProps['aria-checked'] = toggleState.isSelected;
Expand Down
7 changes: 4 additions & 3 deletions packages/@react-aria/calendar/src/useRangeCalendar.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,8 @@ import {useRef} from 'react';
* A range calendar displays one or more date grids and allows users to select a contiguous range of dates.
*/
export function useRangeCalendar<T extends DateValue>(props: AriaRangeCalendarProps<T>, state: RangeCalendarState, ref: RefObject<FocusableElement | null>): CalendarAria {
let res = useCalendarBase(props, state);
let {calendarProps: calendarBaseCalendarProps, ...res} = useCalendarBase(props, state);
let calendarProps = {...calendarBaseCalendarProps};

// We need to ignore virtual pointer events from VoiceOver due to these bugs.
// https://bugs.webkit.org/show_bug.cgi?id=222627
Expand Down Expand Up @@ -62,7 +63,7 @@ export function useRangeCalendar<T extends DateValue>(props: AriaRangeCalendarPr
useEvent(windowRef, 'pointerup', endDragging);

// Also stop range selection on blur, e.g. tabbing away from the calendar.
res.calendarProps.onBlur = e => {
calendarProps.onBlur = e => {
if (!ref.current) {
return;
}
Expand All @@ -78,5 +79,5 @@ export function useRangeCalendar<T extends DateValue>(props: AriaRangeCalendarPr
}
}, {passive: false, capture: true});

return res;
return {...res, calendarProps};
}
29 changes: 18 additions & 11 deletions packages/@react-aria/collections/src/CollectionBuilder.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -47,9 +47,16 @@ export function CollectionBuilder<C extends BaseCollection<object>>(props: Colle

// Otherwise, render a hidden copy of the children so that we can build the collection before constructing the state.
// This should always come before the real DOM content so we have built the collection by the time it renders during SSR.
return (
<CollectionBuilderInner createCollection={props.createCollection} content={props.content}>
{props.children}
</CollectionBuilderInner>
);
}

// This is fine. CollectionDocumentContext never changes after mounting.
// eslint-disable-next-line react-hooks/rules-of-hooks
function CollectionBuilderInner(props) {
// Otherwise, render a hidden copy of the children so that we can build the collection before constructing the state.
// This should always come before the real DOM content so we have built the collection by the time it renders during SSR.
let {collection, document} = useCollectionDocument(props.createCollection);
return (
<>
Expand Down Expand Up @@ -80,7 +87,6 @@ function useSyncExternalStoreFallback<C>(subscribe: (onStoreChange: () => void)
// This is read immediately inside the wrapper, which also runs during render.
// We just need a ref to avoid invalidating the callback itself, which
// would cause React to re-run the callback more than necessary.
// eslint-disable-next-line rulesdir/pure-render
isSSRRef.current = isSSR;

let getSnapshotWrapper = useCallback(() => {
Expand Down Expand Up @@ -109,7 +115,7 @@ function useCollectionDocument<T extends object, C extends BaseCollection<T>>(cr
return collection;
}, [document]);
let getServerSnapshot = useCallback(() => {
document.isSSR = true;
document.setSSR(true);
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

had to introduce this because the React compiler is a bit strict about mutating, I think it should be allowed in this case, but React doesn't know that, so I've tricked it. I had tried storing the document in a ref and editing it that way, which fixes the compiler problem, but it broke some tests, I'm not sure why and it makes me a little worried. This is the closest to what we've tested for years though, so I'm ok with this for now.

return document.getCollection();
}, [document]);
let collection = useSyncExternalStore(subscribe, getSnapshot, getServerSnapshot);
Expand All @@ -132,8 +138,9 @@ function createCollectionNodeClass(type: string): CollectionNodeClass<any> {

function useSSRCollectionNode<T extends Element>(CollectionNodeClass: CollectionNodeClass<T> | string, props: object, ref: ForwardedRef<T>, rendered?: any, children?: ReactNode, render?: (node: Node<any>) => ReactElement) {
// To prevent breaking change, if CollectionNodeClass is a string, create a CollectionNodeClass using the string as the type
if (typeof CollectionNodeClass === 'string') {
CollectionNodeClass = createCollectionNodeClass(CollectionNodeClass);
let CollectionNodeClassLocal = CollectionNodeClass;
if (typeof CollectionNodeClassLocal === 'string') {
CollectionNodeClassLocal = createCollectionNodeClass(CollectionNodeClassLocal);
}

// During SSR, portals are not supported, so the collection children will be wrapped in an SSRContext.
Expand All @@ -142,15 +149,15 @@ function useSSRCollectionNode<T extends Element>(CollectionNodeClass: Collection
// collection by the time we need to use the collection to render to the real DOM.
// After hydration, we switch to client rendering using the portal.
let itemRef = useCallback((element: ElementNode<any> | null) => {
element?.setProps(props, ref, CollectionNodeClass, rendered, render);
}, [props, ref, rendered, render, CollectionNodeClass]);
element?.setProps(props, ref, CollectionNodeClassLocal, rendered, render);
}, [props, ref, rendered, render, CollectionNodeClassLocal]);
let parentNode = useContext(SSRContext);
if (parentNode) {
// Guard against double rendering in strict mode.
let element = parentNode.ownerDocument.nodesByProps.get(props);
if (!element) {
element = parentNode.ownerDocument.createElement(CollectionNodeClass.type);
element.setProps(props, ref, CollectionNodeClass, rendered, render);
element = parentNode.ownerDocument.createElement(CollectionNodeClassLocal.type);
element.setProps(props, ref, CollectionNodeClassLocal, rendered, render);
parentNode.appendChild(element);
parentNode.ownerDocument.updateCollection();
parentNode.ownerDocument.nodesByProps.set(props, element);
Expand All @@ -162,7 +169,7 @@ function useSSRCollectionNode<T extends Element>(CollectionNodeClass: Collection
}

// @ts-ignore
return <CollectionNodeClass.type ref={itemRef}>{children}</CollectionNodeClass.type>;
return <CollectionNodeClassLocal.type ref={itemRef}>{children}</CollectionNodeClassLocal.type>;
}

// eslint-disable-next-line @typescript-eslint/no-unused-vars
Expand Down
4 changes: 4 additions & 0 deletions packages/@react-aria/collections/src/Document.ts
Original file line number Diff line number Diff line change
Expand Up @@ -431,6 +431,10 @@ export class Document<T, C extends BaseCollection<T> = BaseCollection<T>> extend
return true;
}

setSSR(value: boolean): void {
this.isSSR = value;
}

createElement(type: string): ElementNode<T> {
return new ElementNode(type, this);
}
Expand Down
13 changes: 9 additions & 4 deletions packages/@react-aria/color/src/useColorArea.ts
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,12 @@ export function useColorArea(props: AriaColorAreaOptions, state: ColorAreaState)

let {direction, locale} = useLocale();

let [focusedInput, setFocusedInput] = useState<'x' | 'y' | null>(null);
let [focusedInput, _setFocusedInput] = useState<'x' | 'y' | null>(null);
let focusedInputRef = useRef<'x' | 'y' | null>(focusedInput);
let setFocusedInput = useCallback((newFocusedInput: 'x' | 'y' | null) => {
focusedInputRef.current = newFocusedInput;
_setFocusedInput(newFocusedInput);
}, [_setFocusedInput]);
let focusInput = useCallback((inputRef:RefObject<HTMLInputElement | null> = inputXRef) => {
if (inputRef.current) {
focusWithoutScrolling(inputRef.current);
Expand Down Expand Up @@ -157,8 +162,8 @@ export function useColorArea(props: AriaColorAreaOptions, state: ColorAreaState)
}
setValueChangedViaKeyboard(valueChanged);
// set the focused input based on which axis has the greater delta
focusedInput = valueChanged && Math.abs(deltaY) > Math.abs(deltaX) ? 'y' : 'x';
setFocusedInput(focusedInput);
let newFocusedInput = valueChanged && Math.abs(deltaY) > Math.abs(deltaX) ? 'y' as const : 'x' as const;
setFocusedInput(newFocusedInput);
} else {
currentPosition.current.x += (direction === 'rtl' ? -1 : 1) * deltaX / width ;
currentPosition.current.y += deltaY / height;
Expand All @@ -168,7 +173,7 @@ export function useColorArea(props: AriaColorAreaOptions, state: ColorAreaState)
onMoveEnd() {
isOnColorArea.current = false;
state.setDragging(false);
let input = focusedInput === 'x' ? inputXRef : inputYRef;
let input = focusedInputRef.current === 'x' ? inputXRef : inputYRef;
focusInput(input);
}
};
Expand Down
3 changes: 2 additions & 1 deletion packages/@react-aria/color/src/useColorSlider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ export function useColorSlider(props: AriaColorSliderOptions, state: ColorSlider

// @ts-ignore - ignore unused incompatible props
let {groupProps, trackProps, labelProps, outputProps} = useSlider({...props, 'aria-label': ariaLabel}, state, trackRef);
let {inputProps, thumbProps} = useSliderThumb({
let {inputProps: sliderInputProps, thumbProps} = useSliderThumb({
index: 0,
orientation,
isDisabled: props.isDisabled,
Expand All @@ -64,6 +64,7 @@ export function useColorSlider(props: AriaColorSliderOptions, state: ColorSlider
trackRef,
inputRef
}, state);
let inputProps = {...sliderInputProps};

let value = state.getDisplayColor();
let generateBackground = () => {
Expand Down
7 changes: 4 additions & 3 deletions packages/@react-aria/datepicker/src/useDateField.ts
Original file line number Diff line number Diff line change
Expand Up @@ -207,7 +207,8 @@ export interface AriaTimeFieldOptions<T extends TimeValue> extends AriaTimeField
* Each part of a time value is displayed in an individually editable segment.
*/
export function useTimeField<T extends TimeValue>(props: AriaTimeFieldOptions<T>, state: TimeFieldState, ref: RefObject<Element | null>): DateFieldAria {
let res = useDateField(props, state, ref);
res.inputProps.value = state.timeValue?.toString() || '';
return res;
let {inputProps: dateFieldInputProps, ...res} = useDateField(props, state, ref);
let inputProps = {...dateFieldInputProps};
inputProps.value = state.timeValue?.toString() || '';
return {...res, inputProps};
}
3 changes: 2 additions & 1 deletion packages/@react-aria/dnd/src/useDraggableItem.ts
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ const MESSAGES = {
export function useDraggableItem(props: DraggableItemProps, state: DraggableCollectionState): DraggableItemResult {
let stringFormatter = useLocalizedStringFormatter(intlMessages, '@react-aria/dnd');
let isDisabled = state.isDisabled || state.selectionManager.isDisabled(props.key);
let {dragProps, dragButtonProps} = useDrag({
let {dragProps: draggableDragProps, dragButtonProps} = useDrag({
getItems() {
return state.getItems(props.key);
},
Expand All @@ -88,6 +88,7 @@ export function useDraggableItem(props: DraggableItemProps, state: DraggableColl
clearGlobalDnDState();
}
});
let dragProps = {...draggableDragProps};

let item = state.collection.getItem(props.key);
let numKeysForDrag = state.getKeysForDrag(props.key).size;
Expand Down
12 changes: 10 additions & 2 deletions packages/@react-aria/form/src/useFormValidation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,10 @@
*/

import {FormValidationState} from '@react-stately/form';
import {getOwnerDocument, useEffectEvent, useLayoutEffect} from '@react-aria/utils';
import {RefObject, Validation, ValidationResult} from '@react-types/shared';
import {setInteractionModality} from '@react-aria/interactions';
import {useEffect, useRef} from 'react';
import {useEffectEvent, useLayoutEffect} from '@react-aria/utils';

type ValidatableElement = HTMLInputElement | HTMLTextAreaElement | HTMLSelectElement;

Expand Down Expand Up @@ -84,7 +84,15 @@ export function useFormValidation<T>(props: FormValidationProps<T>, state: FormV
return;
}

let form = input.form;
// Uses closest and querySelector instead of just the form property to work around a React compiler bug.
// https://github.com/facebook/react/issues/34891
let form = input.closest('form');
if (!form) {
let formId = input.getAttribute('form');
if (formId) {
form = getOwnerDocument(input).querySelector(`#${formId}`) as HTMLFormElement | null;
}
}

let reset = form?.reset;
if (form) {
Expand Down
4 changes: 2 additions & 2 deletions packages/@react-aria/i18n/src/useDateFormatter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,9 +26,9 @@ export interface DateFormatterOptions extends Intl.DateTimeFormatOptions {
*/
export function useDateFormatter(options?: DateFormatterOptions): DateFormatter {
// Reuse last options object if it is shallowly equal, which allows the useMemo result to also be reused.
options = useDeepMemo(options ?? {}, isEqual);
let memoizedOptions = useDeepMemo(options ?? {}, isEqual);
let {locale} = useLocale();
return useMemo(() => new DateFormatter(locale, options), [locale, options]);
return useMemo(() => new DateFormatter(locale, memoizedOptions), [locale, memoizedOptions]);
}

function isEqual(a: DateFormatterOptions, b: DateFormatterOptions) {
Expand Down
2 changes: 1 addition & 1 deletion packages/@react-aria/interactions/src/PressResponder.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ React.forwardRef(({children, ...props}: PressResponderProps, ref: ForwardedRef<F
}
});

useSyncRef(prevContext, ref);
useSyncRef(prevContext.ref, ref);

useEffect(() => {
if (!isRegistered.current) {
Expand Down
2 changes: 1 addition & 1 deletion packages/@react-aria/interactions/src/useFocusable.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ export let FocusableContext: React.Context<FocusableContextValue | null> = React

function useFocusableContext(ref: RefObject<FocusableElement | null>): FocusableContextValue {
let context = useContext(FocusableContext) || {};
useSyncRef(context, ref);
useSyncRef(context.ref, ref);

// eslint-disable-next-line
let {ref: _, ...otherProps} = context;
Expand Down
2 changes: 1 addition & 1 deletion packages/@react-aria/interactions/src/usePress.ts
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,7 @@ function usePressResponderContext(props: PressHookProps): PressHookProps {
props = mergeProps(contextProps, props) as PressHookProps;
register();
}
useSyncRef(context, props.ref);
useSyncRef(context.ref, props.ref);

return props;
}
Expand Down
3 changes: 2 additions & 1 deletion packages/@react-aria/menu/src/useMenuTrigger.ts
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,8 @@ export function useMenuTrigger<T>(props: AriaMenuTriggerProps, state: MenuTrigge
} = props;

let menuTriggerId = useId();
let {triggerProps, overlayProps} = useOverlayTrigger({type}, state, ref);
let {triggerProps: overlayTriggerProps, overlayProps} = useOverlayTrigger({type}, state, ref);
let triggerProps = {...overlayTriggerProps};

let onKeyDown = (e) => {
if (isDisabled) {
Expand Down
5 changes: 3 additions & 2 deletions packages/@react-aria/select/src/useSelect.ts
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,7 @@ export function useSelect<T, M extends SelectionMode = 'single'>(props: AriaSele
if (state.selectionManager.selectionMode === 'multiple') {
return;
}

switch (e.key) {
case 'ArrowLeft': {
// prevent scrolling containers
Expand All @@ -124,13 +124,14 @@ export function useSelect<T, M extends SelectionMode = 'single'>(props: AriaSele
}
};

let {typeSelectProps} = useTypeSelect({
let {typeSelectProps: selectTypeSelectProps} = useTypeSelect({
keyboardDelegate: delegate,
selectionManager: state.selectionManager,
onTypeSelect(key) {
state.setSelectedKey(key);
}
});
let typeSelectProps = {...selectTypeSelectProps};

let {isInvalid, validationErrors, validationDetails} = state.displayValidation;
let {labelProps, fieldProps, descriptionProps, errorMessageProps} = useField({
Expand Down
8 changes: 6 additions & 2 deletions packages/@react-aria/slider/test/useSlider.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,9 @@ describe('useSlider', () => {
function Example(props) {
let trackRef = useRef(null);
let state = useSliderState({...props, numberFormatter});
stateRef.current = state;
React.useEffect(() => {
stateRef.current = state;
}, [state]);
let {trackProps} = useSlider(props, state, trackRef);
return <div data-testid="track" ref={trackRef} {...trackProps} />;
}
Expand Down Expand Up @@ -182,7 +184,9 @@ describe('useSlider', () => {
function Example(props) {
let trackRef = useRef(null);
let state = useSliderState({...props, numberFormatter});
stateRef.current = state;
React.useEffect(() => {
stateRef.current = state;
}, [state]);
let {trackProps} = useSlider(props, state, trackRef);
return <div data-testid="track" ref={trackRef} {...trackProps} />;
}
Expand Down
8 changes: 6 additions & 2 deletions packages/@react-aria/slider/test/useSliderThumb.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -113,7 +113,9 @@ describe('useSliderThumb', () => {
let input0Ref = useRef(null);
let input1Ref = useRef(null);
let state = useSliderState({...props, numberFormatter});
stateRef.current = state;
React.useEffect(() => {
stateRef.current = state;
}, [state]);
let {trackProps, thumbProps: commonThumbProps} = useSlider(props, state, trackRef);
let {inputProps: input0Props, thumbProps: thumb0Props} = useSliderThumb({
...commonThumbProps,
Expand Down Expand Up @@ -273,7 +275,9 @@ describe('useSliderThumb', () => {
let trackRef = useRef(null);
let inputRef = useRef(null);
let state = useSliderState({...props, numberFormatter});
stateRef.current = state;
React.useEffect(() => {
stateRef.current = state;
}, [state]);
let {trackProps} = useSlider(props, state, trackRef);
let {inputProps, thumbProps} = useSliderThumb({
...props,
Expand Down
Loading