Skip to content

Commit 58825f5

Browse files
committed
Add Cmd.debounce
1 parent 203440e commit 58825f5

3 files changed

Lines changed: 56 additions & 0 deletions

File tree

src/Fabulous.Tests/CmdTests.fs

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
namespace Fabulous.Tests
2+
3+
open Fabulous
4+
open NUnit.Framework
5+
6+
type CmdTestsMsg = NewValue of int
7+
8+
module CmdTestsHelper =
9+
let execute dispatch (cmd: Cmd<'msg>) =
10+
for sub in cmd do
11+
sub dispatch
12+
13+
[<TestFixture>]
14+
type ``Cmd tests``() =
15+
[<Test>]
16+
member _.``Cmd.debounce only dispatch the last message``() =
17+
async {
18+
let mutable actualValue = None
19+
let dispatch msg =
20+
if actualValue.IsNone then
21+
actualValue <- Some msg
22+
23+
let triggerCmd = Cmd.debounce 100 NewValue
24+
25+
triggerCmd 1 |> CmdTestsHelper.execute dispatch
26+
do! Async.Sleep 50
27+
triggerCmd 2 |> CmdTestsHelper.execute dispatch
28+
do! Async.Sleep 75
29+
triggerCmd 3 |> CmdTestsHelper.execute dispatch
30+
do! Async.Sleep 125
31+
32+
Assert.AreEqual(Some(NewValue 3), actualValue)
33+
}

src/Fabulous.Tests/Fabulous.Tests.fsproj

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
<Compile Include="AttributesTests.fs" />
1616
<Compile Include="ViewTests.fs" />
1717
<Compile Include="ArrayTests.fs" />
18+
<Compile Include="CmdTests.fs" />
1819
</ItemGroup>
1920
<ItemGroup>
2021
<PackageReference Include="BenchmarkDotNet" />

src/Fabulous/Cmd.fs

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
namespace Fabulous
22

3+
open System.Threading
34
open System.Threading.Tasks
45

56
/// Dispatch - feed new message into the processing loop
@@ -104,3 +105,24 @@ module Cmd =
104105
dispatch(failure ex)
105106
}
106107
|> ignore ]
108+
109+
/// Command to issue a message if no other message has been issued within the specified timeout
110+
let debounce (timeout: int) (fn: 'value -> 'msg): 'value -> Cmd<'msg> =
111+
let mutable cts: CancellationTokenSource = null
112+
113+
fun (value: 'value) ->
114+
[ fun dispatch ->
115+
if cts <> null then
116+
cts.Cancel()
117+
cts.Dispose()
118+
119+
cts <- new CancellationTokenSource()
120+
121+
Async.Start(
122+
async {
123+
do! Async.Sleep(timeout)
124+
dispatch (fn value)
125+
},
126+
cts.Token
127+
)
128+
]

0 commit comments

Comments
 (0)