Skip to content

v0.5.0 -- With love and effection!

Choose a tag to compare

@trusktr trusktr released this 14 Dec 09:51
· 7 commits to main since this release

What's Changed

  • feat: add a new @effect decorator for reacting to signals and memos. by @trusktr in #14

Details

feat: add a new @effect decorator (see README) for reacting to signals and memos, with startEffects() and stopEffects() functions for cleaning up or restarting effects. The gist:

import {signal, memo, effect, stopEffects, startEffects} from 'classy-solid'

class Effectionate {
  @signal a = 1
  @signal b = 2

  @memo get sum() {
    return this.a + this.b
  }

  @effect logSum() {
    console.log('sum:', this.sum)
  }
}

const eff = new Effectionate() // logs "sum: 3"

eff.a = 4 // logs "sum: 6"

// Later, stop effects (if the instances is unreferenced, everything is garbage collected)
stopEffects()

eff.b = 4 // does not log anything

// Later, restart effects
startEffects() // logs "sum: 8"

The stopEffects and startEffects functions

Other changes:

  • feat: added .startEffects() method to Effectful() mixin and Effects class for restarting stopped effects.
  • feat: added .clearEffects() method to Effectful() mixin and Effects class for stopping effects and removing them (startEffects() will not restart them again).
  • Introduced a metadata shim until native support is available, and used metadata to refactored decorators to simplify initialization and finalization processes.
  • Added tests for invalid usages, and for subclassing behavior for all decorators.
  • Updated signalify to apply batch() so that if a signal setter writes to a superclass signal, it doesn't cause multiple updates.
  • Improved overall type definitions and metadata management for better clarity and maintainability.

BREAKING:

  • Updated the @memo decorator to remove support for usage on class fields.
    • migration: @memo foo = () => a() + b() should be changed to @memo get foo() { return a() + b(); }
  • The .stopEffects() method of the Effectful() mixin (or Effects class) now keeps previous effect functions stored so that .startEffects() can restart them. This means that for any existing usages that called .stopEffects() and then use .createEffect() to create new effects will now be restarting the old effects as well as adding new effects, causing unwated effects or duplicate effects.
    • migration: Switch to using the .clearEffects() method instead, which deletes effect functions after stopping them. Example, using Custom Elements:
      Before:
      class MyEl extends Effectful(HTMLElement) {
        // ...signals/memos/etc...
       
        connectedCallback() {
          this.createEffect(() => {...})
          this.createEffect(() => {...})
          this.createEffect(() => {...})
        }
       
        disconnectedCallback() {
          this.stopEffects()
        }
      }
      After:
        disconnectedCallback() {
          this.clearEffects() // use this instead
        }
      Or better yet, use the new @effect decorator, with the plain startEffect/stopEffects functions:
      class MyEl extends HTMLElement {
        // ...signals/memos/etc...
       
        @effect first() {...}
        @effect second() {...}
        @effect third() {...}
        
        connectedCallback() {
          startEffects(this)
        }
        
        disconnectedCallback() {
          stopEffects(this)
        }
      }

Full Changelog: v0.4.4...v0.5.0