diff --git a/packages/react/src/player/create-player.tsx b/packages/react/src/player/create-player.tsx index d74b9307..216ed347 100644 --- a/packages/react/src/player/create-player.tsx +++ b/packages/react/src/player/create-player.tsx @@ -16,7 +16,7 @@ import type { InferStoreState } from '@videojs/store'; import { combine, createStore } from '@videojs/store'; import { useStore } from '@videojs/store/react'; import type { FC, ReactNode } from 'react'; -import { useEffect, useState } from 'react'; +import { useEffect, useMemo, useState } from 'react'; import { useDestroy } from '../utils/use-destroy'; import { Container, PlayerContextProvider, useMedia, usePlayerContext } from './context'; @@ -91,11 +91,12 @@ export function createPlayer(config: CreatePlayerConfig): Cr return store.attach({ media, container }); }, [media, container, store]); - return ( - - {children} - + const value = useMemo( + () => ({ store, media, setMedia, container, setContainer, popupGroup }), + [store, media, container, popupGroup] ); + + return {children}; } if (__DEV__ && config.displayName) { diff --git a/packages/react/src/player/tests/create-player.test.tsx b/packages/react/src/player/tests/create-player.test.tsx index f981ad82..c6ae916f 100644 --- a/packages/react/src/player/tests/create-player.test.tsx +++ b/packages/react/src/player/tests/create-player.test.tsx @@ -2,7 +2,7 @@ import { act, render, renderHook } from '@testing-library/react'; import type { PlayerStore } from '@videojs/core/dom'; import { defineSlice } from '@videojs/store'; import type { ReactNode } from 'react'; -import { StrictMode } from 'react'; +import { StrictMode, useState } from 'react'; import { describe, expect, it, vi } from 'vitest'; import { usePlayerContext } from '../context'; import { createPlayer } from '../create-player'; @@ -188,6 +188,41 @@ describe('createPlayer', () => { expect(container.querySelector('[data-testid="child"]')).toBeTruthy(); }); + + it('provides a stable context value across parent re-renders (fix for #1296)', () => { + const { Provider } = createPlayer({ features: [mockSlice] }); + + const receivedValues: unknown[] = []; + + function ContextConsumer() { + const ctx = usePlayerContext(); + receivedValues.push(ctx); + return null; + } + + let forceParentRerender!: () => void; + function Parent() { + const [, setTick] = useState(0); + forceParentRerender = () => setTick((t) => t + 1); + return ( + + + + ); + } + + render(); + + const valueAfterMount = receivedValues[receivedValues.length - 1]; + + act(() => forceParentRerender()); + act(() => forceParentRerender()); + act(() => forceParentRerender()); + + const valueAfterRerenders = receivedValues[receivedValues.length - 1]; + + expect(valueAfterRerenders).toBe(valueAfterMount); + }); }); describe('usePlayer', () => {