diff --git a/change/@fluentui-react-utilities-3e7e29b4-ccde-4269-ac7f-8adf2333171e.json b/change/@fluentui-react-utilities-3e7e29b4-ccde-4269-ac7f-8adf2333171e.json new file mode 100644 index 0000000000000..24466911ead6d --- /dev/null +++ b/change/@fluentui-react-utilities-3e7e29b4-ccde-4269-ac7f-8adf2333171e.json @@ -0,0 +1,7 @@ +{ + "type": "patch", + "comment": "feat: defers useControllableState state to initializer method", + "packageName": "@fluentui/react-utilities", + "email": "bernardo.sunderhus@gmail.com", + "dependentChangeType": "patch" +} diff --git a/packages/react-components/react-utilities/src/hooks/useControllableState.ts b/packages/react-components/react-utilities/src/hooks/useControllableState.ts index 6e47b1c1e8bde..af679fd104899 100644 --- a/packages/react-components/react-utilities/src/hooks/useControllableState.ts +++ b/packages/react-components/react-utilities/src/hooks/useControllableState.ts @@ -39,11 +39,19 @@ export type UseControllableStateOptions = { export const useControllableState = ( options: UseControllableStateOptions, ): [State, React.Dispatch>] => { - const initialState = typeof options.defaultState === 'undefined' ? options.initialState : options.defaultState; - const [internalState, setInternalState] = React.useState(initialState); + const [internalState, setInternalState] = React.useState(() => { + if (options.defaultState === undefined) { + return options.initialState; + } + return isInitializer(options.defaultState) ? options.defaultState() : options.defaultState; + }); return useIsControlled(options.state) ? [options.state, noop] : [internalState, setInternalState]; }; +function isInitializer(value: State | (() => State)): value is () => State { + return typeof value === 'function'; +} + function noop() { /* noop */ } @@ -53,7 +61,7 @@ function noop() { * Prints an error when isControlled value switches between subsequent renders * @returns - whether the value is controlled */ -const useIsControlled = (controlledValue?: V): controlledValue is V => { +const useIsControlled = (controlledValue: V | undefined): controlledValue is V => { const [isControlled] = React.useState(() => controlledValue !== undefined); if (process.env.NODE_ENV !== 'production') {