Skip to content

Commit 9ab9c60

Browse files
committed
Fix issue for Cmd in init
1 parent 4dd4d31 commit 9ab9c60

File tree

5 files changed

+44
-21
lines changed

5 files changed

+44
-21
lines changed

CHANGELOG.md

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,11 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
99

1010
_No unreleased changes_
1111

12+
## [3.0.0-pre9] - 2024-11-08
13+
14+
### Fixed
15+
- Fixed an issue where using Cmd in init would not refresh the view by @TimLariviere
16+
1217
## [3.0.0-pre8] - 2024-11-07
1318

1419
### Changed
@@ -157,7 +162,8 @@ _No unreleased changes_
157162
### Changed
158163
- Fabulous.XamarinForms & Fabulous.MauiControls have been moved been out of the Fabulous repository. Find them in their own repositories: [https://github.com/fabulous-dev/Fabulous.XamarinForms](https://github.com/fabulous-dev/Fabulous.XamarinForms) / [https://github.com/fabulous-dev/Fabulous.MauiControls](https://github.com/fabulous-dev/Fabulous.MauiControls)
159164

160-
[unreleased]: https://github.com/fabulous-dev/Fabulous/compare/3.0.0-pre8...HEAD
165+
[unreleased]: https://github.com/fabulous-dev/Fabulous/compare/3.0.0-pre9...HEAD
166+
[3.0.0-pre9]: https://github.com/fabulous-dev/Fabulous/releases/tag/3.0.0-pre9
161167
[3.0.0-pre8]: https://github.com/fabulous-dev/Fabulous/releases/tag/3.0.0-pre8
162168
[3.0.0-pre7]: https://github.com/fabulous-dev/Fabulous/releases/tag/3.0.0-pre7
163169
[3.0.0-pre6]: https://github.com/fabulous-dev/Fabulous/releases/tag/3.0.0-pre6

src/Fabulous/Components/Component.fs

Lines changed: 27 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,9 @@ type Component
2222
let mutable _view = null
2323
let mutable _contextSubscription: IDisposable = null
2424

25+
let mutable _isReadyForRenderRequest = false
26+
let mutable _pendingRenderRequested = false
27+
2528
member private this.MergeAttributes(rootWidget: Widget, componentWidgetOpt: Widget voption) =
2629
match componentWidgetOpt with
2730
| ValueNone -> struct (rootWidget.ScalarAttributes, rootWidget.WidgetAttributes, rootWidget.WidgetCollectionAttributes)
@@ -60,6 +63,9 @@ type Component
6063
struct (scalars, widgets, widgetColls)
6164

6265
member this.CreateView(componentWidget: Widget voption) =
66+
_isReadyForRenderRequest <- false
67+
_contextSubscription <- _context.RenderNeeded.Subscribe(this.Render)
68+
6369
let struct (envContext, treeContext, context, rootWidget) =
6470
_body.Invoke(_envContext, _treeContext, _context)
6571

@@ -87,11 +93,20 @@ type Component
8793
widgetDef.CreateView(rootWidget, envContext, treeContext, ValueNone)
8894

8995
_view <- view
90-
_contextSubscription <- _context.RenderNeeded.Subscribe(this.Render)
96+
_isReadyForRenderRequest <- true
97+
98+
// ComponentContext.SetNeedsRender has been called before the view is created
99+
// We need to re-render the component now because the state has changed before we were ready
100+
if _pendingRenderRequested then
101+
_pendingRenderRequested <- false
102+
this.Render()
91103

92104
struct (node, view)
93105

94106
member this.AttachView(componentWidget: Widget, view: obj) =
107+
_isReadyForRenderRequest <- false
108+
_contextSubscription <- _context.RenderNeeded.Subscribe(this.Render)
109+
95110
let struct (envContext, treeContext, context, rootWidget) =
96111
_body.Invoke(_envContext, _treeContext, _context)
97112

@@ -119,7 +134,13 @@ type Component
119134
widgetDef.AttachView(rootWidget, envContext, treeContext, ValueNone, view)
120135

121136
_view <- view
122-
_contextSubscription <- _context.RenderNeeded.Subscribe(this.Render)
137+
_isReadyForRenderRequest <- true
138+
139+
// ComponentContext.SetNeedsRender has been called before the view is created
140+
// We need to re-render the component now because the state has changed before we were ready
141+
if _pendingRenderRequested then
142+
_pendingRenderRequested <- false
143+
this.Render()
123144

124145
node
125146

@@ -139,6 +160,7 @@ type Component
139160

140161
if prevContext <> context then
141162
_contextSubscription.Dispose()
163+
prevContext.Dispose()
142164
_contextSubscription <- context.RenderNeeded.Subscribe(this.Render)
143165
_context <- context
144166

@@ -164,8 +186,10 @@ type Component
164186
interface IDisposable with
165187
member this.Dispose() = this.Dispose()
166188

167-
member this.Render _ =
189+
member this.Render() =
168190
if isNull _body then
169191
() // Component has been disposed
192+
else if not _isReadyForRenderRequest then
193+
_pendingRenderRequested <- true
170194
else
171195
treeContext.SyncAction(this.RenderInternal)

src/Fabulous/Components/ComponentContext.fs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -68,9 +68,9 @@ type ComponentContext(initialSize: int) =
6868
this.SetValueInternal(key, value)
6969
this.NeedsRender()
7070

71-
member this.LinkDisposable(key: string, disposable: unit -> IDisposable) =
71+
member this.LinkDisposable<'T when 'T :> IDisposable>(key: string, disposable: unit -> 'T) =
7272
if disposables.ContainsKey(key) then
73-
disposables[key]
73+
disposables[key] :?> 'T
7474
else
7575
let disposable = disposable()
7676
disposables[key] <- disposable

src/Fabulous/Components/Mvu.fs

Lines changed: 6 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -30,35 +30,26 @@ type MvuExtensions =
3030
| ValueNone ->
3131
let struct (program, arg) = fn.Invoke()
3232

33-
let programObj: Program<obj, obj, obj> =
34-
{ Init = fun arg -> let model, cmd = program.Init(unbox arg) in (box model, Cmd.map box cmd)
35-
Update = fun (msg, model) -> let model, cmd = program.Update(unbox msg, unbox model) in (box model, Cmd.map box cmd)
36-
Subscribe = fun model -> Sub.map "mvu" box (program.Subscribe(unbox model))
37-
Logger = program.Logger
38-
ExceptionHandler = program.ExceptionHandler }
39-
4033
let runner =
4134
context.LinkDisposable(
4235
"runner",
4336
fun () ->
4437
let getModel () =
4538
match context.TryGetValue<ModelValue<'model>>(key) with
4639
| ValueNone -> failwith("Model not found in ComponentContext " + context.Id.ToString())
47-
| ValueSome(ModelValue model) -> box model
40+
| ValueSome(ModelValue model) -> model
4841

49-
let setModel v =
50-
context.SetValue(key, ModelValue(unbox<'model> v))
51-
context.NeedsRender()
42+
let setModel v = context.SetValue(key, ModelValue v)
5243

53-
let runner = new Runner<obj, obj, obj>(getModel, setModel, programObj)
54-
runner.Start(arg)
55-
runner
44+
new Runner<'arg, 'model, 'msg>(getModel, setModel, program)
5645
)
5746

5847
// Redirect messages to runner
5948
let treeContext =
6049
{ treeContext with
61-
Dispatch = (runner :?> Runner<obj, obj, obj>).Dispatch }
50+
Dispatch = unbox >> runner.Dispatch }
51+
52+
runner.Start(arg)
6253

6354
let (ModelValue state) = context.TryGetValue(key).Value
6455

src/Fabulous/Runner.fs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,8 @@ type Runner<'arg, 'model, 'msg>(getState: unit -> 'model, setState: 'model -> un
2727
let newModel, cmd = program.Update(lastMsg.Value, model)
2828
let subs = program.Subscribe(newModel)
2929

30+
printfn $"Updating model. Was %A{model}, Is %A{newModel}"
31+
3032
setState newModel
3133

3234
_activeSubs <- Sub.Internal.diff _activeSubs subs |> Sub.Internal.Fx.change onError dispatch

0 commit comments

Comments
 (0)