diff --git a/packages/mui-base/src/utils/useControllableReducer.ts b/packages/mui-base/src/utils/useControllableReducer.ts index 790719a937279b..c5abfaca0c5ba3 100644 --- a/packages/mui-base/src/utils/useControllableReducer.ts +++ b/packages/mui-base/src/utils/useControllableReducer.ts @@ -156,6 +156,33 @@ export function useControllableReducer< actionContext, } = parameters; + const controlledPropsRef = React.useRef(controlledProps); + + if (process.env.NODE_ENV !== 'production') { + // eslint-disable-next-line react-hooks/rules-of-hooks + React.useEffect(() => { + Object.keys(controlledProps).forEach((key) => { + if ( + (controlledPropsRef.current as Record)[key] !== undefined && + (controlledProps as Record)[key] === undefined + ) { + console.error( + 'MUI: useControllableReducer is changing a controlled prop to be uncontrolled', + ); + } + + if ( + (controlledPropsRef.current as Record)[key] === undefined && + (controlledProps as Record)[key] !== undefined + ) { + console.error( + 'MUI: useControllableReducer is changing an uncontrolled prop to be controlled', + ); + } + }); + }, [controlledProps]); + } + // The reducer that is passed to React.useReducer is wrapped with a function that augments the state with controlled values. const reducerWithControlledState = React.useCallback( (state: State, action: ActionWithContext) => {