Giter Club home page Giter Club logo

fable.signalr's Introduction

Fable.SignalR Nuget

Fable bindings for the SignalR client, a wrapper for the .NET client, and ASP.NET Core/Giraffe/Saturn wrappers for SignalR server hubs.

The full documentation can be found here.

On the client

let textDisplay = React.functionComponent(fun (input: {| count: int; text: string |}) ->
    React.fragment [
        Html.div input.count
        Html.div input.text
    ])

let buttons = React.functionComponent(fun (input: {| count: int; hub: Hub<Action,Response> |}) ->
    React.fragment [
        Html.button [
            prop.text "Increment"
            prop.onClick <| fun _ -> input.hub.current.sendNow (Action.IncrementCount input.count)
        ]
        Html.button [
            prop.text "Decrement"
            prop.onClick <| fun _ -> input.hub.current.sendNow (Action.DecrementCount input.count)
        ]
        Html.button [
            prop.text "Get Random Character"
            prop.onClick <| fun _ -> input.hub.current.sendNow Action.RandomCharacter
        ]
    ])

let render = React.functionComponent(fun () ->
    let count,setCount = React.useState 0
    let text,setText = React.useState ""

    let hub =
        React.useSignalR<Action,Response>(fun hub -> 
            hub.withUrl(Endpoints.Root)
                .withAutomaticReconnect()
                .configureLogging(LogLevel.Debug)
                .onMessage <|
                    function
                    | Response.NewCount i -> setCount i
                    | Response.RandomCharacter str -> setText str
        )
            
    Html.div [
        prop.children [
            textDisplay {| count = count; text = text |}
            buttons {| count = count; hub = hub |}
        ]
    ])

On the server

module SignalRHub =
    open FSharp.Control.Tasks.V2

    let update (msg: Action) =
        match msg with
        | Action.IncrementCount i -> Response.NewCount(i + 1)
        | Action.DecrementCount i -> Response.NewCount(i - 1)
        | Action.RandomCharacter ->
            let characters = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"
            
            System.Random().Next(0,characters.Length-1)
            |> fun i -> characters.ToCharArray().[i]
            |> string
            |> Response.RandomCharacter

    let invoke (msg: Action) _ =
        task { return update msg }

    let send (msg: Action) (hubContext: FableHub<Action,Response>) =
        update msg
        |> hubContext.Clients.Caller.Send

application {
    use_signalr (
        configure_signalr {
            endpoint Endpoints.Root
            send SignalRHub.send
            invoke SignalRHub.invoke
        }
    )
    ...
}

The shared file

[<RequireQualifiedAccess>]
type Action =
    | IncrementCount of int
    | DecrementCount of int
    | RandomCharacter

[<RequireQualifiedAccess>]
type Response =
    | NewCount of int
    | RandomCharacter of string

module Endpoints =
    let [<Literal>] Root = "/SignalR"

fable.signalr's People

Contributors

kerams avatar prunkles avatar shmew avatar stroborobo avatar theimowski avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar

fable.signalr's Issues

AddSignalR and UseSignalR overloads must match

Description

Reporting this because it took me a couple hours to figure out.

One must be sure to invoke the same AddSignalR and UseSignalR overloads, otherwise confusing dependency resolution errors occur. For example, if one invokes:

services.AddSignalR(signalRSettings, streamToClient)

// Oops, forgot to pass in streamToClient
app.UseSignalR(signalRSettings)

The following runtime error occurs when attempting to connect to the hub:

fail: Microsoft.AspNetCore.SignalR.HubConnectionHandler[1]
      Error when dispatching 'OnConnectedAsync' on hub.
System.InvalidOperationException: Unable to resolve service for type 'Fable.SignalR.BaseFableHubOptions`2[Microsoft.FSharp.Core.Unit,Microsoft.FSharp.Core.Unit]' while attempting to activate 'Fable.SignalR.BaseFableHub`2[Microsoft.FSharp.Core.Unit,Microsoft.FSharp.Core.Unit]'.
   at Microsoft.Extensions.DependencyInjection.ActivatorUtilities.GetService(IServiceProvider sp, Type type, Type requiredBy, Boolean isDefaultParameterRequired)
   at lambda_method(Closure , IServiceProvider , Object[] )
   at Microsoft.AspNetCore.SignalR.Internal.DefaultHubActivator`1.Create()
   at Microsoft.AspNetCore.SignalR.Internal.DefaultHubDispatcher`1.OnConnectedAsync(HubConnectionContext connection)
   at Microsoft.AspNetCore.SignalR.Internal.DefaultHubDispatcher`1.OnConnectedAsync(HubConnectionContext connection)
   at Microsoft.AspNetCore.SignalR.HubConnectionHandler`1.RunHubAsync(HubConnectionContext connection)

Steps to reproduce

  1. Per the above, you just need a mismatch between AddSignalR and UseSignalR overloads, which causes a mismatch between types registered and types requested during resolution

Expected behavior

At minimum, it would be nice to have a good runtime error message guide the dev here. But I'm also not sure why the split between send/invoke and streaming exists. If Settings had streaming-related properties in it too, there would be no need for multiple overloads and hence no chance of mismatching calls.

Getting that the Namespace Http is missing, when I use the Emlish Package

" ./.fable/Fable.SignalR.0.4.0/HubConnection.fs (306,50) error FSHARP: The namespace or module 'Http' is not defined. Maybe you want one of the following: "

So maybe some package is missing?

paket dependencies forthe client:

group Client
FSharp.Core
Fable.Core
Fable.Elmish.Debugger
Fable.Elmish.React
Fable.Elmish.HMR
Thoth.Fetch
Fulma
Fable.FontAwesome.Free
Fable.SignalR.Elmish

Support cancellation of streams created with StreamFrom in .NET client

This relates to the .NET client - I am not sure if it affects other clients.

Is your feature request related to a problem?

IHubConnection<...> has a StreamFrom that accepts a CancellationToken and forwards onto the SignalR hub's StreamAsync method, but HubConnection<...>.StreamFrom does not likewise accept a CancellationToken. This means clients cannot cancel streams.

Describe the solution you'd like

Cancellation should be exposed to clients, allowing them to proactively cancel a stream.

Describe alternatives you've considered

I've hacked this into my own copy of the code to prove it would work how I'd expect (how a raw SignalR stream works, basically). It required changes to both client and server.

Question: does client package assume the use of server package?

Hello,

Thanks for this library. First time user here, so apologies if I'm asking something dumb.

I was trying to determine from the docs whether the client library requires the use of the server library, or whether it could integrate with an existing SignalR backend.

Context: I already have a SignalR stream API that is using a channel rather than async enumerable. It doesn't seem as straightforward as I'd hoped to convert from a channel-based implementation to one based on async enumerable, and if I was to convert my backend, Fable.SignalR seems to only support the latter. So that got me wondering whether I could just integrate directly.

Q: Send broadcast messages from REST API

Hi,
is it possible to broadcast messages to clients from my REST API?
E.g.:

  1. Clients adds a Todo item to a list via REST API
  2. Server responds with OK (or whatever)
  3. Server broadcasts new Todo item to all (other) clients via SignalR.

My problem is, that I don't have access to the hub context. So I'm not able to invoke
let send (msg: Action) (hubContext: FableHub<Action, Response>) = ...
from inside my REST API.

My server currently uses the Saturn framework. Like this:

let app =
    application {
        use_signalr (
            configure_signalr {
                endpoint Blizzard.Endpoints.Root
                send SignalRHub.send
                invoke SignalRHub.invoke
            }
        )
        url "http://0.0.0.0:8085"
        use_router webApp
        memory_cache
        use_static "public"
        use_gzip
    }

When searching for mixing REST and SignalR with ASPNetCore the solution looks like this:

https://stackoverflow.com/a/12369683/2356048

The point is, that there is a global static class GlobalHost where the hub context can be retrieved.

Is there a way to do something similar?

Allow server streaming implementations to detect cancellation

Is your feature request related to a problem?

This could reasonably be considered a bug, but I'm submitting as a feature request...

The only CancellationToken available to server stream implementations is the one inside FableHub<...>.HubContext.ConnectionAborted. This CT is provided by SignalR and exposed by Fable.SignalR. However, it is not sufficient for a server stream to base its life time on this CT because it only triggers if the connection itself is severed. It is not triggered in the event of a client explicitly cancelling a stream like this:

let cancellationTokenSource = new CancellationTokenSource();
let stream = hubConnection.StreamAsync<int>("Counter", 10, 500, cancellationTokenSource.Token)

// later
cancellationTokenSource.Cancel() |> ignore

The requirement for that to work is that the hub's streaming method must include a CancellationToken parameter, but Fable.SignalR's hubs do not declare this parameter.

See the docs on streaming for more info.

Describe the solution you'd like

Streaming methods in the various hubs should include a CancellationToken parameter that is then passed into the stream implementation. Unfortunately, this means that the streaming function signature will need to change to include the CT. This will be a breaking change, but unavoidable as far as I can tell.

Describe alternatives you've considered

The only alternative would be to add a property to the FableHub interface, but that would mean:

  1. The property is only relevant to stream implementations. e.g. it could be called StreamCancelled
  2. The property would exist in the FableHub rather than the HubContext, so it would feel a bit weird
  3. The implementation of stream methods would need to create a new object instance with an updated CT before forwarding the call onto the stream implementation
  4. It would be easy for stream implementations to ignore or miss the significance of this CT

To me, it's cleaner and clearer to change the existing function signature, making it clear to implementations that they really should care about that CT and not ignore it.

Additional context

SignalR & SAFE Stack (Saturn/Giraffe) & Net5.0

Description

I get following compile error:
error NU1202: Package Microsoft.AspNetCore.Authentication.JwtBearer 5.0.1 is not compatible with netcoreapp3.1 (.NETCoreApp,Version=v3.1). Package Microsoft.AspNetCore.Authentication.JwtBearer 5.0.1 supports: net5.0 (.NETCoreApp,Version=v5.0)

Steps to reproduce

  1. Install the SAFE-Stack template
  2. Create new project from the template
  3. Follow the installation instructions for Fable.SignalR
  4. Compile with dotnet fake build -t run

Produces the shown error.

Expected behavior

I'm not sure. I'm pretty new to all this Fable/F#/netcore stuff. As far as I understand the SAFE template uses netcoreapp3.1 and it looks like Fable.SignalR adds a dependency (via Microsoft.AspNetCore.Authentication.JwtBearer) to net5.0.
So, there is no way to use Fable.SignalR with netcoreapp3.1?

Or could I try to install an older version? If so, which one?

I would be grateful for any advice. If it's not a Fable.SignalR problem, please let me know. It's very confusing for a newbie to see who is responsible for which package etc.

Q: How do I send a message from a handler function?

When handling a message how do I get hold of the actual hub so I can send a message? The simple counter example only updates when receiving data, it doesn't ever send anything back from those handlers as I can see.

My first naive approach was this:

    let hub =
      React.useSignalR<Shared.Command, Shared.Event>(fun hub -> 
        hubBuilder.withUrl(sprintf "http://localhost:5000%s" Endpoints.Root)
          .withAutomaticReconnect()
          .configureLogging(LogLevel.Debug)
          .onMessage (handleEvent hub)

When I started implementing handleEvent I realized I just had access to the hub builder, not the actual hub. So what would be the recommended way of getting access to the hub in handleEvent?

Unable to resolve BaseFableHubOptions when trying to connect

Description

I followed the basic setup in the docs, but when the client attempts to connect to the hub, the api throws the following exception:

Microsoft.AspNetCore.SignalR.HubConnectionHandler[1]
      Error when dispatching 'OnConnectedAsync' on hub.
      System.InvalidOperationException: Unable to resolve service for type 'Fable.SignalR.BaseFableHubOptions`2[Api.SignalRHub+SignalRAction,Api.SignalRHub+Response]' while attempting to activate 'Fable.SignalR.BaseFableHub`2[Api.SignalRHub+SignalRAction,Api.SignalRHub+Response]'.
         at Microsoft.Extensions.DependencyInjection.ActivatorUtilities.GetService(IServiceProvider sp, Type type, Type requiredBy, Boolean isDefaultParameterRequired)
         at lambda_method44(Closure , IServiceProvider , Object[] )
         at Microsoft.AspNetCore.SignalR.Internal.DefaultHubActivator`1.Create()
         at Microsoft.AspNetCore.SignalR.Internal.DefaultHubDispatcher`1.OnConnectedAsync(HubConnectionContext connection)
         at Microsoft.AspNetCore.SignalR.Internal.DefaultHubDispatcher`1.OnConnectedAsync(HubConnectionContext connection)
         at Microsoft.AspNetCore.SignalR.HubConnectionHandler`1.RunHubAsync(HubConnectionContext connection)

Appreciate any help!

Latest Fable.SignalR.AspNetCore requires Fable.Remoting.MsgPack below 1.7

Given following dependencies:

source https://api.nuget.org/v3/index.json
framework: net5.0
storage: none

nuget Fable.Remoting.Giraffe
nuget Saturn
nuget Expecto

nuget Fable.FontAwesome.Free
nuget Fable.Mocha
nuget Fable.Remoting.Client
nuget Fable.SignalR.Saturn
nuget Fable.SignalR.Feliz
nuget Feliz.Bulma
nuget Fulma

nuget Fake.Core.ReleaseNotes
nuget Fake.Core.Target
nuget Fake.DotNet.Cli
nuget Farmer

when I'm trying to do paket update, it fails to find a valid resolution due to:

Paket may still find a valid resolution, but this might take a while.
  Conflict detected:
   - Fable.SignalR.AspNetCore 0.11.2 requested package Fable.Remoting.MsgPack: >= 1.6.2 < 1.7
   - Fable.Remoting.Client 7.6.0 requested package Fable.Remoting.MsgPack: >= 1.8
   - Fable.SignalR 0.11.2 requested package Fable.Remoting.MsgPack: >= 1.6.2 < 2.0

I think this is due to the project having a ~> pinned dependency on locked version of Fable.Remoting.MsgPack, hence in nuspec it ends up as < 1.7
If there's no breaking change in that dependency, then possibly loosening that restriction could help fix the issue.

As a workaround I could try defining separate paket groups for Client and Server dependencies, but I'd rather have a single group unless there's a good reason not to.

Elmish example for server streaming

Could you give the full demo of using SignalR with Elmish?
I can't understand the example (https://shmew.github.io/Fable.SignalR/#/signalr-client/streaming-server), what does mean 'Subscription' there

 | StartServerStream ->
        let subscriber dispatch =
            { next = SignalRStreamMsg >> dispatch
              complete = fun () -> StreamStatus.Finished |> StreamStatus |> dispatch
              error = StreamStatus.Error >> StreamStatus >> dispatch }

        { model with StreamStatus = StreamStatus.Streaming }
        , Cmd.SignalR.streamFrom model.Hub StreamFrom.Action.GenInts **Subscription** subscriber

How to get this object?

Can not build the project on linux

Description

When I execute fake build it throws an error:

Script reported an error:
-> BuildFailedException: Target 'YarnInstall' failed.
-> One or more errors occurred. (Start of process '/home/prunkles/Develop/repos/Shmew/Fable.SignalR/packages/tooling/Yarnpkg.Yarn/content/bin/yarn.cmd' failed.)
-> Start of process '/home/prunkles/Develop/repos/Shmew/Fable.SignalR/packages/tooling/Yarnpkg.Yarn/content/bin/yarn.cmd' failed.
-> Win32Exception: Permission denied

Steps to reproduce

  1. Be on Linux
  2. Execute fake build

Expected behavior

Successful compilation of the project.

Additional context

OS: Manjaro Linux x86_64
Kernel: 4.19.126-1-MANJARO

Split into bindings and a library

I think that it would be nice if the library was split into two parts:

  1. Fable bindings. Literally a 1-to-1 copy of the corresponding JS library (@microsoft/signalr), without any additional idiomatic F# features, but with types.
    And according to the de facto standard, it should be called as Fable.Import.SignalR.
  2. The library as it is now. Action/Response feature, client-server interaction, and so on.
    I'm not sure if keeping the Fable.SignalR name in this case is a good idea, but I have no suggestions yet.

My point is to provide also just Fable bindings if someone needs it, but doesn't need the whole set of library functions.

Authorization is not available

Description

The NormalFableHub isn't marked with the [<Authorize>] attribute, so the Context.User fields are empty.

Steps to reproduce

  1. Copy the demo project
  2. Add authentication to the client using
    hub.wuthUrl("url", fun conn -> conn.accessTokenFactory(fun() -> TOKEN)
    and to the server with
    services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme).AddJwtBearer(configureJwt))
  3. Try to send any request and check the hub.Context.User fields
  4. See empty fields

Additional context

I'm not entirely sure if this is the problem, but I think it makes sense.

405 error with fable client

When following the counter example outlined in the documentation everything works fine with the dotnet client but the fable client throws a 405 error when negotiating the connection. This is because it sends an options request and not a get request. I got it working by disabling the negotiation phase.

This is somewhat unfortunate since the microsoft documentation tells you that you get this error because you dont have cors enabled and sends you down a different rabbit hole: https://docs.microsoft.com/en-us/aspnet/core/signalr/troubleshoot?view=aspnetcore-6.0

Response code 405

Http status code 405 - Method Not Allowed

The app doesn't have CORS enabled

Authorization Documentation does not match codebase

Description

In the Authorization documentation here:

https://shmew.github.io/Fable.SignalR/#/authorization

It says for ASP.NET Core/Giraffe you can use the SignalR.ConfigBuilder, however the example code is invalid. The "Build" method at the end of the DSL chain is internal in the ConfigBuilder type, so ConfigBuilder doesn't seem to be usable.

Steps to reproduce

Just use the example from the documentation in a project that isn't considered internal to the libraries.

Expected behavior

Build to be public so it can be called and ConfigBuilder used.

Q: IDisposable

From the docs:

type Model =
    { Count: int
      Text: string
      Hub: Elmish.Hub<Action,Response> option }

    // This only works if you're using Feliz.UseElmish or Feliz.ElmishComponents!
    //
    // If you're using the traditional elmish model you will need to clean this up yourself.
    interface System.IDisposable with
        member this.Dispose () =
            this.Hub |> Option.iter (fun hub -> hub.Dispose())

What does mean? When do I have to dispose the hub? Every time I create a new model? Or only once at the end of my application?

Add .NET client

Enable users to call Fable.SignalR hubs from the .NET client.

Trouble getting regular Dotnet Client working

Hello. I have successfully managed to get the Dotnet.Elmish client working as expected, but I can't seem to get the normal Dotnet client working. Invoking an action on the hub seems to work, but Sending an action doesn't. As far as I can tell, the request is successfully sent from the client, but the server never does anything with it.

Additionally, I can't seem to get Message Pack working either. The client always thinks that the server is using plain json serialization.

I've attached a minimal demo project for these problems. https://github.com/kaeedo/FableSignalRDotnetMinimal

I fear I'm missing some simple configuration, but since it works as expected when using the dotnet.elmish client, I thought I'd ask anyway.

Thanks.

Bump versions to work with ASP .NET Core 6 / .NET 6

Is your feature request related to a problem?

Yes. Trying to add Fable.SignalR.Saturn (and therefore .AspNetCore) with Saturn 0.16.x / Giraffe 6.x doesn't work:

 - Fable.SignalR.AspNetCore 0.11.5 requested package System.Text.Encodings.Web: >= 5.0 < 6.0
 - System.Text.Json 6.0.2 requested package System.Text.Encodings.Web: >= 6.0
 - Microsoft.ApplicationInsights.Profiler.Core 2.3.1 requested package system.text.encodings.web: >= 5.0.1

Describe the solution you'd like

If System.Text.Encodings.Web supported 6.x as well, this issue might go away (I suspect that there may be other deps that also need promoting).

Describe alternatives you've considered

Downgrading our project to .NET 5, but this would be highly undesirable.

Compile error: missing module http

Description

I tried to use Fable.SignalR in my project with the steps given in the docs, but I am running into compile errors.

Steps to reproduce

I've added Fable.SignalR, SignalR.Elmish, SignalR.Feliz. I've even tried to add SimpleHttp...

Error message

.fable/Fable.SignalR.0.11.5/HubConnection.fs(332,46): (332,50) error FSHARP: The namespace or module 'Http' is not defined. Maybe you want one of the following: HttpClient (code 39)

Q: Use with non-Fable/dotnet client?

Hey, thanks for this project! I love the neat, functional interface over SignalR.

I want to use the server-side bindings with a native app not made in .NET or in Fable. I've set up a small hub with Giraffe, and I'm able to connect to it with Postman but my initial handshake isn't going through. I know (for example) Fable.Remoting allows raw HTTP connections and has a small guide to it, so is something like that possible with Fable.SignalR? If so, is there something I'd need to set up to get the WS working?

Here's what I get when I try to send a handshake to the hub:

image

How to set "target" in message from client to server

Hi, first, thanks for this library, great work and documentation.

How do I set the target of a message? I've been through the source code, and got myself a little lost.

Following the docs, I can get a message like the one on the right in the screenshot below, but my server is expecting a message in the format on the left. We'll be changing the protocol once we have a PoC working, this is a learning phase. Thank you!

image

I'm using Elmish, but can drop back to native if it gives me access to a richer/more flexible API.

Thanks

Q: Broadcast message to clients as a side-effect in REST API

Hi,
is it possible to broadcast messages to clients from my REST API?
E.g.:

  1. Clients adds a Todo item to a list via REST API
  2. Server responds with OK (or whatever)
  3. Server broadcasts new Todo item to all (other) clients via SignalR.

My problem is, that I don't have access to the hub context. So I'm not able to invoke
let send (msg: Action) (hubContext: FableHub<Action, Response>) = ...
from inside my REST API.

My server currently uses the Saturn framework. Like this:

let app =
    application {
        use_signalr (
            configure_signalr {
                endpoint Blizzard.Endpoints.Root
                send SignalRHub.send
                invoke SignalRHub.invoke
            }
        )
        url "http://0.0.0.0:8085"
        use_router webApp
        memory_cache
        use_static "public"
        use_gzip
    }

When searching for mixing REST and SignalR with ASPNetCore the solution looks like this:

https://stackoverflow.com/a/12369683/2356048

The point is, that there is a global static class GlobalHost where the hub context can be retrieved.

Is there a way to do something similar?

Fable.Elmish 4.0 support

PS E:\Webdev\Fable\CFR-In-Fable\src\Server> paket add Fable.SignalR.Elmish
Paket version 7.2.1+8e4eb74b42fbd45f39f7afce9184c16ebb65f16c
Adding package 'Fable.SignalR.Elmish'
Resolving dependency graph...
  Conflict detected:
   - Fable.SignalR.Elmish 0.11.5 requested package Fable.Elmish: >= 3.1 < 4.0
   - Elmish.Bridge.Client 7.0.2 requested package Fable.Elmish: >= 4.0
   - Fable.Elmish.React 4.0 requested package Fable.Elmish: >= 4.0

At this point the library is out of date and needs upgrading.

    Fable.FastCheck (0.33)
      Fable.Core (>= 3.2.8 < 4.0)
      Fable.Elmish (>= 3.1 < 4.0)
      Fable.Promise (>= 2.2.2 < 3.0)
      FSharp.Core (>= 4.7.2)

In particular the library that is blocking us here is this one. Since FastCheck is just for testing, would it be possible to omit it?

Incorrect package minimum for dependency

This project needs Microsoft.AspNetCore.SignalR.Protocols.NewtonsoftJson 5.0.7 yet in NuGet the package ranges are (>= 5.0.0 && < 6.0.0).

When using NuGet client this causes runtime errors as NuGet defaults to 5.0.0 for this transitive when it needs at least 5.0.7.

How to capture current React Component state inside SignalR hub onMessage handler?

Apologies for a noob question but I can't get my head around following:
In the sample code you're sending request to increment counter from client, the counter is incremented on server, and new counter is sent back to client in response and then set inside React Component state:

let render = React.functionComponent(fun () ->
    let count,setCount = React.useState 0
    
    let hub =
        React.useSignalR<Action,Response>(fun hub -> 
            hub.withUrl(Endpoints.Root)
                .withAutomaticReconnect()
                .configureLogging(LogLevel.Debug)
                .onMessage <|
                    function
                    | Response.NewCount i -> setCount i
                    | Response.RandomCharacter str -> setText str
        )

now say I'd like to capture current count state when handling the message, e.g. do increment on client side:

                    // ignore counter from server and try using current state - but count is always 0
                    | Response.NewCount _ -> setCount (count + 1)

But this approach doesn't work - count evaluates always to 0.

The approach works fine with bare state hook:

[<ReactComponent>]
let Counter () =
    let x, setX = React.useState 0

    Html.div [
        Html.h1 (string x)
        Html.button [
           // works as expected
           prop.onClick (fun _ -> setX (x + 1))
        ]
    ]

Is that by design? How can I work around that?

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.