From 94b05a789a1fa2ca72ea91ca18c65523a3ee1fad Mon Sep 17 00:00:00 2001 From: ogolknev Date: Fri, 31 Jul 2026 13:31:40 +0300 Subject: [PATCH 1/2] fix(core): sanitize React key warning getter in dev --- packages/core/core.ts | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/packages/core/core.ts b/packages/core/core.ts index be0b4ece..8c1b3a3c 100644 --- a/packages/core/core.ts +++ b/packages/core/core.ts @@ -113,6 +113,15 @@ export function withBemMod( return jsx(ModifiedComponent, Object.assign({}, props, { className })) } + if (__DEV__) { + // Remove React's key warning getter before passing props to jsx + const keyGetter = Object.getOwnPropertyDescriptor(props, 'key')?.get + const isReactWarning + = keyGetter && 'isReactWarning' in keyGetter && keyGetter.isReactWarning + + props = isReactWarning ? { ...props } : props + } + return jsx(WrappedComponent, props) } From 250c65574ca117b8f5230de806822ef5468f2f08 Mon Sep 17 00:00:00 2001 From: ogolknev Date: Fri, 7 Aug 2026 21:02:27 +0300 Subject: [PATCH 2/2] fix: handle React key spread warning in core and di --- packages/core/core.ts | 9 +++------ packages/core/test/withBemMod.test.tsx | 10 ++++++++++ packages/di/di.tsx | 6 ++++++ packages/di/test/di.test.tsx | 10 ++++++++++ 4 files changed, 29 insertions(+), 6 deletions(-) diff --git a/packages/core/core.ts b/packages/core/core.ts index 8c1b3a3c..cc73bb54 100644 --- a/packages/core/core.ts +++ b/packages/core/core.ts @@ -114,12 +114,9 @@ export function withBemMod( } if (__DEV__) { - // Remove React's key warning getter before passing props to jsx - const keyGetter = Object.getOwnPropertyDescriptor(props, 'key')?.get - const isReactWarning - = keyGetter && 'isReactWarning' in keyGetter && keyGetter.isReactWarning - - props = isReactWarning ? { ...props } : props + // React adds a non-enumerable `key` getter to props, passing them to `jsx` + // as is triggers a false "key spread" warning. + if ('key' in props) props = Object.assign({}, props) } return jsx(WrappedComponent, props) diff --git a/packages/core/test/withBemMod.test.tsx b/packages/core/test/withBemMod.test.tsx index e42764af..9d07703c 100644 --- a/packages/core/test/withBemMod.test.tsx +++ b/packages/core/test/withBemMod.test.tsx @@ -62,6 +62,16 @@ describe('withBemMod', () => { ) }) + test('should not warn about key spread for unmatched prop', () => { + const spy = jest.spyOn(console, 'error').mockImplementation(() => {}) + const WBCM = withBemMod(presenter(), { theme: 'normal' })(Presenter) + + render() + + expect(spy).not.toHaveBeenCalled() + spy.mockRestore() + }) + test('should not initialized after change props', () => { const init = jest.fn() const Enhanced = withBemMod( diff --git a/packages/di/di.tsx b/packages/di/di.tsx index 5afd4c8b..c6f6aa89 100644 --- a/packages/di/di.tsx +++ b/packages/di/di.tsx @@ -18,6 +18,12 @@ export function withRegistry() { const RegistryResolver: FC

= (props) => { const providedRegistriesRef = useRef(null) + if (__DEV__) { + // React adds a non-enumerable `key` getter to props, passing them to `jsx` + // as is triggers a false "key spread" warning. + if ('key' in props) props = Object.assign({}, props) + } + return ( {(contextRegistries) => { diff --git a/packages/di/test/di.test.tsx b/packages/di/test/di.test.tsx index 9d9f14a1..a2f7d42f 100644 --- a/packages/di/test/di.test.tsx +++ b/packages/di/test/di.test.tsx @@ -113,6 +113,16 @@ describe('@bem-react/di', () => { }) describe('withRegistry', () => { + test('should not warn about key spread', () => { + const spy = jest.spyOn(console, 'error').mockImplementation(() => {}) + const App = withRegistry(new Registry({ id: 'registry' }))(() => null) + + render() + + expect(spy).not.toHaveBeenCalled() + spy.mockRestore() + }) + describe('useRegistry', () => { test('should pull component from registry', () => { const registry = new Registry({ id: 'registry' })