If the Elmish state should be updated by the event but not the view a wrapper component might do:
[<Import("cloneElement", from="react")>]
let cloneElement(element: ReactElement, props: obj, [<ParamList>] children: obj) = jsNative
type RequestAnimationFrameState<'a> = {
props: 'a
}
type RequestAnimationFrameComponent<'a>(initialProps) as this =
inherit React.Component<'a, RequestAnimationFrameState<'a>>(initialProps)
let mutable frameRequest = None
do
this.setInitState({ props = initialProps})
override this.shouldComponentUpdate(nextProps, nextState) =
let propsChanged = (* Compare keys in nextProps and this.props like PureComponent does *)
if propsChanged then
match frameRequest with
| Some r ->
window.cancelAnimationFrame r
| _ -> ()
frameRequest <- Some (window.requestAnimationFrame( fun _ -> this.setState({ props = this.props })))
let stateChanged = not (obj.ReferenceEquals(this.state, nextState))
stateChanged
override this.render() =
cloneElement(this.children.[0], this.state.props, [||])
If each event completly erase the previous one (last one wins) even updating the elmish state can be bypassed:
type Msg = | FrequentMsg of string
// Wrap a dispatcher to dispatch using `requestAnimationFrame` (If multiple dispatch are initiated within a frame only the latest one will apply)
let dispatchWithAnimationFrame (dispatch: Dispatch<_>) =
let mutable lastRequest = None
fun msg ->
match lastRequest with
| Some r -> window.cancelAnimationFrame r
| _ -> ()
lastRequest <- Some (window.requestAnimationFrame (fun _ -> dispatch msg))
let view dispatch =
let onFastEvent arg = (dispatchWithAnimationFrame dispatch) (FrequentMsg arg)
fun model ->
// rest of render()