Here's what a counter example looks like -
counter count = do
button [onClick] [text (show count)]
counter (count + 1)
Check out a comparison with elm-architecture at https://ajnsit.github.io/concur-documentation/ch03-01-replic....Here's what a counter example looks like -
counter count = do
button [onClick] [text (show count)]
counter (count + 1)
Check out a comparison with elm-architecture at https://ajnsit.github.io/concur-documentation/ch03-01-replic....- How do I manage state that isn't local to one widget? A counter's nice and local, but I don't see how application-wide state gets handled.
- How are data fetching and other asynchronous actions wired in?
It could use some type signatures, but it makes sense.
As for managing state, my understanding of the Elm Architecture is that there is one "global" state data structure, and various parts of it are handed down from parent to child. So my question would be the opposite of yours: what if I want local state? Is that possible? There are situations where some toggle being on or off isn't very important and keeping track of it in a global data structure is burdensome
Currently the only thing to take care of is - when a child widget returns some value to the parent, if you want to reinvoke the child widget and somehow restore the previous local state of the child widget, you need to have sent that local state out to the parent previously. This means that you either add the local state to the child widget's return value, or use something like a wire to directly send the state to the parent or something else.
I am working on adding automatically persisted local state to Concur which would greatly simplify this. It would provide an API similar to hooks' useState (and the react bindings will actually use hooks for this).
Fortunately, you can make your own abstractions in Concur. For example, you can use a "Wire" - which lets multiple child components share and update parts of the parent's state (https://github.com/purescript-concur/purescript-concur-core/...). Note how this abstraction just uses the high level Concur API, and doesn't depend on the UI backend. With a wire the code might look something like this -
-- A wire into parent's state, accessible using `with`, and updateable using `wire.send`
counter wire = with wire \i -> do
button [onClick] [text (show i)]
wire.send (i+1)
And you can compose several counters that share state like this (the first two counters will increment together - -- Parent component creates a wire using `local` and an initial value
local 0 \w -> div []
[ counter w
, counter w
, some
, other
, widgets
]
-- Beyond this point the local state is gone and can't be accessed
doSomethingElse
2. Concur widgets can perform sync effect as well as async effects using `liftEffect` and `liftAffect`, and the results of those actions are available within the monad just like other widget results. Does that answer your question?Also not having to expose all the action datatypes when they are only being used in a single place can really improve code structure.