0

I have a class that keeps input events and lets me query the state.

class Input {

  btn() { return this._btn }

  _release() { this._btn = -1 }

  _press() { this._btn = 0 }

  listen() {
    document.addEventListener('keydown', e => this._press())
    document.addEventListener('keyup', e => this._release())
  }

  update() {
   if (this._btn >= 0) this._btn++
  }
}

I use this class like this:

  let input = new Input()
  input.listen()

  function update_every_frame() {
    input.update()
  }
  function check_for_input() {
    if (input.btn() > 0) {
      console.log('here')
    }
  }

So using solid style coding I want to make a signal that changes whenever an input btn is pressed:

  let [input, setInput] = createSignal(new Input(), { equals: false })

  function update_every_frame() {
    setInput(input => { input.update(); return input })
  }


  const check_for_input = () => { return input().btn() }

Now check_for_input is a reactive property that returns the button presses. Except this property up dates every frame because I call input.update every frame.

I don't want granular signals at the data level, where I pollute the pure data class with signals. Be cause I want to make a data class and test it independent of the library.

So how do I make granular signals that works for properties of a whole pure class.

Edit

Also for example how do I create signals or memo's for an array, or a getter property on a class so the signals are updated accordingly when the class updates it's properties:

class Test {
   array: Array

   a: number = 0
   get computed(): {
      return this.a < 4 ? 1 : 0
   }

   update() {
      this.a = 10
   }
}

let [instance, setInstance] = createSignal(new Test(), { equals: false })

let arraySignal = createMemo(() => instance().array)
let computedSignal = createMemo(() =>
  instance.computed)

How does computedSignal update on this method call:

setInstance(instance => instance.update())
eguneys
  • 6,028
  • 7
  • 31
  • 63
  • I'm not quite sure what you're asking, but my sense is you want to use the `equals` function in the `createSignal` options. Does something like `let [input, setInput] = createSignal(new Input(), { equals: (prev, next) => prev.btn() !== next.btn() })` accomplish what you want? – Nick Apr 09 '22 at 01:50
  • Correction, the condition is probably `equals: (prev, next) => prev.btn() === next.btn() ` – Nick Apr 09 '22 at 01:56
  • I think that could work, what would be the equals function if I was testing an array, and pushing items to the array – eguneys Apr 09 '22 at 04:37
  • Also there is one problem, I have other properties on this class, so when I call a method multiple properties might change. But each signal doesn't get updated because their setInput function is not called even though underlying class has changed. – eguneys Apr 09 '22 at 05:03
  • The challenge here, I believe, is you either have to treat the signal as _immutable_ and make sure it's reference is updated when you want it to change, _or_ you have to provide explicit instructions to to the `exact` function to perform the required diffing. I don't think there's really any other way for Solid to tell when the class instance has "changed" – Nick Apr 09 '22 at 14:43

1 Answers1

2

One way you can do it is like this:

import {createMutable} from 'solid-js/store'
import {createEffect} from 'solid-js'

class Foo {
  // any properties here
  whatever = 123

  constructor() {
    return createMutable(this)
  }
}

const f = new Foo

createEffect(() => console.log(f.whatever))

f.whatever++ // reactive

or to keep the class really pure:

import {createMutable} from 'solid-js/store'
import {createEffect} from 'solid-js'

class Foo {
  // any properties here
  whatever = 123
}

const f = createMutable(new Foo)

createEffect(() => console.log(f.whatever))

f.whatever++ // reactive

You said you don't want to make signal for every property, but with classy-solid you can do it in a way that still feels like writing a regular class:

import {reactive, signal} from 'classy-solid'

@reactive
class Foo {
  @signal whatever = 123
}

const f = new Foo

createEffect(() => console.log(f.whatever))

f.whatever++ // reactive
trusktr
  • 44,284
  • 53
  • 191
  • 263
  • Not sure that's what you're looking for, actually it seems you have more than one question in your question. :) – trusktr Apr 18 '22 at 04:39