Skip to content

Commit

Permalink
Fix issue with self in functional components
Browse files Browse the repository at this point in the history
  • Loading branch information
somebee committed Jan 15, 2024
1 parent 8a3ae98 commit 669161e
Show file tree
Hide file tree
Showing 4 changed files with 49 additions and 2 deletions.
5 changes: 5 additions & 0 deletions packages/imba/changelog.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,11 @@

## Unreleased

* Fix issue with self in functional components.

Event handlers inside functional components could refer to to the wrong
`self` if called multiple times with different `self` values.

* Major performance fix for certain css selectors.

When using selectors like `^@hover prop:value` Imba would compile
Expand Down
19 changes: 17 additions & 2 deletions packages/imba/src/compiler/nodes.imba1
Original file line number Diff line number Diff line change
Expand Up @@ -4448,8 +4448,11 @@ export class IsolatedFunc < Func
if let leaks = @scope.@leaks
@leaks = []
leaks.forEach do |shadow,source|
shadow.@proxy = @params.at(@params.count,yes)
@leaks.push(source)
if shadow.@name == 'self'
@useSelf = shadow
else
shadow.@proxy = @params.at(@params.count,yes)
@leaks.push(source)
self

export class IifeFunc < Func
Expand Down Expand Up @@ -9373,6 +9376,13 @@ export class TagModifier < TagPart

if @name isa IsolatedFunc
@value = @name

let root = STACK.parents(TagLike)[0]
if root
root.set(memoSelf: yes)
# should only be needed _if_ self is referenced? But this is a micro optimization
let op = @value.@scope.@context = OP('.',root.parentCache,STR('this'))

@name = STR('$_')
@params = ListNode.new([@value].concat(@value.leaks or []))

Expand Down Expand Up @@ -9590,6 +9600,7 @@ export class TagHandlerCallback < ValueNode
val = val.value

if val isa Func
# TODO Warn / error if func has arguments
val = val.body

# If the value is just a variable we can add it directly?
Expand Down Expand Up @@ -10772,6 +10783,10 @@ export class Tag < TagLike

# console.log "IS INLINE? {o:inline} {STACK.isExpression} {!!@consumedBy} {!!@parent} {isDetached}"

# if option(:memoSelf)
if !parent and option(:memoSelf) # scope__.@context # and scope__.@context.@reference
add "{parentCache}.this=this"

if !@consumedBy
@ref = "{tvar}"

Expand Down
1 change: 1 addition & 0 deletions packages/imba/src/imba/events/core.imba
Original file line number Diff line number Diff line change
Expand Up @@ -201,6 +201,7 @@ export def use_events
yes

# could cache similar event handlers with the same parts
# Should be possible to remove closure from EventHandler
export class EventHandler
def constructor params,closure
self.params = params
Expand Down
26 changes: 26 additions & 0 deletions packages/imba/test/apps/rendering/functional-self.imba
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@

class Item
count = 0
def node val
<div @click=(count++)>

tag App
# the default value of label will be inherited
# from the closest parent that has a label property
prop label = #context.label
item = new Item
options = {}

def render
<self>
<(item.node(options))>

test do
let app = new <App>
ok app.item.count == 0
app.children[0].click()
ok app.item.count == 1
app.item = new Item
app.render!
app.children[0].click()
ok app.item.count == 1

0 comments on commit 669161e

Please sign in to comment.