@@ -5,7 +5,13 @@ import type {
55 HvComponentOnUpdate ,
66 HvComponentProps ,
77} from 'hyperview/src/types' ;
8- import React , { useEffect , useRef , useState } from 'react' ;
8+ import React , {
9+ useCallback ,
10+ useEffect ,
11+ useMemo ,
12+ useRef ,
13+ useState ,
14+ } from 'react' ;
915import { TouchableWithoutFeedback , View } from 'react-native' ;
1016import { LOCAL_NAME } from 'hyperview/src/types' ;
1117import { createEventHandler } from 'hyperview/src/core/hyper-ref' ;
@@ -20,44 +26,74 @@ const HvOption = (props: HvComponentProps) => {
2026 const { element, onUpdate, options, stylesheets } = props ;
2127 const [ pressed , setPressed ] = useState ( false ) ;
2228 const { onSelect, onToggle } = options ;
23- const value = element . getAttribute ( 'value' ) ;
24- const selected = element . getAttribute ( 'selected' ) === 'true' ;
29+ const value = useMemo ( ( ) => element . getAttribute ( 'value' ) , [ element ] ) ;
30+ const selected = useMemo ( ( ) => element . getAttribute ( 'selected' ) === 'true' , [
31+ element ,
32+ ] ) ;
2533 const prevSelected = useRef ( selected ) ;
2634
2735 // Updates options with pressed/selected state, so that child element can render
2836 // using the appropriate modifier styles.
29- const newOptions = {
30- ...options ,
31- pressed,
32- pressedSelected : pressed && selected ,
33- selected,
34- } as const ;
37+ const newOptions = useMemo ( ( ) => {
38+ return {
39+ ...options ,
40+ pressed,
41+ pressedSelected : pressed && selected ,
42+ selected,
43+ } as const ;
44+ } , [ options , pressed , selected ] ) ;
45+
3546 const componentProps = useProps ( element , stylesheets , newOptions ) ;
3647
48+ const flex = useMemo ( ( ) => {
49+ // eslint-disable-next-line @typescript-eslint/ban-ts-comment
50+ // @ts -ignore TODO: fix this
51+ return componentProps . style ?. flex ;
52+ } , [
53+ // eslint-disable-next-line @typescript-eslint/ban-ts-comment
54+ // @ts -ignore TODO: fix this
55+ componentProps . style ?. flex ,
56+ ] ) ;
57+
58+ const handlePress = useCallback ( ( ) => {
59+ if ( onSelect ) {
60+ // Updates the DOM state, causing this element to re-render as selected.
61+ // Used in select-single context.
62+ onSelect ( value ) ;
63+ }
64+ if ( onToggle ) {
65+ // Updates the DOM state, toggling this element.
66+ // Used in select-multiple context.
67+ onToggle ( value ) ;
68+ }
69+ } , [ onSelect , onToggle , value ] ) ;
70+
71+ const handlePressIn = useCallback ( ( ) => setPressed ( true ) , [ ] ) ;
72+ const handlePressOut = useCallback ( ( ) => setPressed ( false ) , [ ] ) ;
73+
3774 // Option renders as an outer TouchableWithoutFeedback view and inner view.
3875 // The outer view handles presses, the inner view handles styling.
39- const outerProps = {
40- onPress : createEventHandler ( ( ) => {
41- if ( onSelect ) {
42- // Updates the DOM state, causing this element to re-render as selected.
43- // Used in select-single context.
44- onSelect ( value ) ;
45- }
46- if ( onToggle ) {
47- // Updates the DOM state, toggling this element.
48- // Used in select-multiple context.
49- onToggle ( value ) ;
50- }
51- } , true ) ,
52- onPressIn : createEventHandler ( ( ) => setPressed ( true ) ) ,
53- onPressOut : createEventHandler ( ( ) => setPressed ( false ) ) ,
54- style : { } ,
55- } ;
56- if ( componentProps . style && componentProps . style . flex ) {
57- // Flex is a style that needs to be lifted from the inner component to the outer
58- // component to ensure proper layout.
59- outerProps . style = { flex : componentProps . style . flex } ;
60- }
76+ const outerProps = useMemo ( ( ) => {
77+ return {
78+ onPress : createEventHandler ( handlePress , true ) ,
79+ onPressIn : createEventHandler ( handlePressIn ) ,
80+ onPressOut : createEventHandler ( handlePressOut ) ,
81+
82+ // Flex is a style that needs to be lifted from the inner component to the outer
83+ // component to ensure proper layout.
84+ style : flex ? { flex } : { } ,
85+ } ;
86+ } , [ flex , handlePress , handlePressIn , handlePressOut ] ) ;
87+
88+ // TODO: Replace with <HvChildren>
89+ const children = useMemo ( ( ) => {
90+ return Render . renderChildren (
91+ element ,
92+ stylesheets ,
93+ onUpdate as HvComponentOnUpdate ,
94+ newOptions ,
95+ ) ;
96+ } , [ element , newOptions , onUpdate , stylesheets ] ) ;
6197
6298 useEffect ( ( ) => {
6399 if ( selected && ! prevSelected . current ) {
@@ -70,20 +106,13 @@ const HvOption = (props: HvComponentProps) => {
70106 prevSelected . current = selected ;
71107 } , [ element , onUpdate , selected ] ) ;
72108
73- // TODO: Replace with <HvChildren>
74- return React . createElement (
75- TouchableWithoutFeedback ,
76- outerProps ,
77- React . createElement (
78- View ,
79- componentProps ,
80- ...Render . renderChildren (
81- element ,
82- stylesheets ,
83- onUpdate as HvComponentOnUpdate ,
84- newOptions ,
85- ) ,
86- ) ,
109+ const view = useMemo ( ( ) => {
110+ return React . createElement ( View , componentProps , ...children ) ;
111+ } , [ componentProps , children ] ) ;
112+
113+ return useMemo (
114+ ( ) => React . createElement ( TouchableWithoutFeedback , outerProps , view ) ,
115+ [ outerProps , view ] ,
87116 ) ;
88117} ;
89118
0 commit comments