From ad69b451e6a068dc8b3b7cf6a4eb6f6b10b32ec7 Mon Sep 17 00:00:00 2001 From: Christian Pillsbury Date: Mon, 8 Sep 2025 16:28:16 -0700 Subject: [PATCH] refactor(react): implement hook-style component architecture for PlayButton MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Add playButtonStateDef with keys, stateTransform, and requestMethods - Refactor usePlayButtonState to use shallowEqual optimization - Migrate from useMediaDispatch to useMediaStore pattern - Create request methods factory for consistent state management - Improve type safety and performance with optimized state selection This continues the gradual migration to hook-style architecture that can be shared between HTML and React implementations. 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude --- .../react/react/src/components/PlayButton.tsx | 63 ++++++++++++++----- 1 file changed, 47 insertions(+), 16 deletions(-) diff --git a/packages/react/react/src/components/PlayButton.tsx b/packages/react/react/src/components/PlayButton.tsx index 656175e4..e29155b5 100644 --- a/packages/react/react/src/components/PlayButton.tsx +++ b/packages/react/react/src/components/PlayButton.tsx @@ -1,25 +1,56 @@ -import { useMediaDispatch, useMediaSelector } from '@vjs-10/react-media-store'; +import { + shallowEqual, + // useMediaDispatch, + useMediaSelector, + useMediaStore, +} from '@vjs-10/react-media-store'; import * as React from 'react'; import { toConnectedComponent } from '../utils/component-factory'; -export const usePlayButtonState = (_props: any) => { - /** @TODO Fix type issues with hooks (CJP) */ - const paused = useMediaSelector( - (state: any) => typeof state.paused !== 'boolean' || state.paused, - ) as boolean; +/** + * PlayButton state hook - equivalent to React's usePlayButtonState + * Handles media store state subscription and transformation + */ +export const playButtonStateDef = { + keys: ['paused'], + stateTransform: (rawState: any) => ({ + paused: rawState.paused ?? true, + }), + /** @TODO Consider "promoting" this up to state-mediator defs + media store (CJP) */ + requestMethods: (mediaStore: ReturnType) => { + return { + requestPlay() { + const type = 'playrequest'; + mediaStore.dispatch({ type }); + }, + requestPause() { + const type = 'pauserequest'; + mediaStore.dispatch({ type }); + }, + }; + }, +} as const; - const dispatch = useMediaDispatch(); - const requestPlay = React.useCallback(() => { - dispatch({ type: 'playrequest' }); - }, [dispatch]); - const requestPause = React.useCallback(() => { - dispatch({ type: 'pauserequest' }); - }, [dispatch]); +export const usePlayButtonState = (_props: any) => { + const mediaStore = useMediaStore(); + /** @TODO Fix type issues with hooks (CJP) */ + const mediaState = useMediaSelector( + playButtonStateDef.stateTransform, + shallowEqual, + ); + + const [methods, setMethods] = React.useState( + playButtonStateDef.requestMethods(mediaStore), + ); + + React.useEffect(() => { + setMethods(playButtonStateDef.requestMethods(mediaStore)); + }, [mediaStore]); return { - paused, - requestPlay, - requestPause, + paused: mediaState.paused, + requestPlay: methods.requestPlay, + requestPause: methods.requestPause, } as const; };