Effects

Step 5: Effects

The last piece: an effect is a side effect that runs immediately and then re-runs whenever any state it depends on changes, logging, rendering, syncing to storage. It is the bridge from reactive values back out to the real world, and it must be disposable so it can stop.

  • create_effect(fn, sources): run fn once now, subscribe it to re-run on every change of each source in sources, and return a dispose function that cancels all of those subscriptions
Hints
Starter code
class Subject:
    def __init__(self):
        self._observers = []

    def subscribe(self, observer):
        self._observers.append(observer)
        def unsubscribe():
            if observer in self._observers:
                self._observers.remove(observer)
        return unsubscribe

    def notify(self, *args):
        for observer in self._observers:
            observer(*args)


class Observable:
    def __init__(self, value=None):
        self._value = value
        self._subject = Subject()

    def get(self):
        return self._value

    def subscribe(self, observer):
        return self._subject.subscribe(observer)

    def set(self, value):
        if value == self._value:
            return
        self._value = value
        self._subject.notify(value)


def create_effect(fn, sources):
    """Run fn now and on every change of any source; return a dispose function."""
    # TODO: invoke fn once right away so the effect reflects the current state, then
    #   register on every source in sources an observer that ignores whatever value
    #   it is handed and simply re-runs fn, collecting the unsubscribe handle each
    #   subscription returns. Hand back a function that fires all of those handles.
    pass
Write it on a laptop

The editor and the test runner need a wide screen. Open this page on a desktop browser and your progress will be waiting.