getify / TNG-Hooks

Provides React-inspired 'hooks' like useState(..) for stand-alone functions
MIT License
1.01k stars 38 forks source link

Feature: hooks fire events #15

Open getify opened 5 years ago

getify commented 5 years ago

I have an idea for a couple of features that I think would make debugging and testing of hooks much better. Want to sketch them out here and get feedback.

  1. First, I'm thinking these features would be turned off by default, mostly because they have some performance implications.

    One way of toggling this on and off would be to just have separate builds of the library. So, like a "debug" build of the code has all the extra bits in it, but the production version wouldn't have those bits included.

    Another option is to have a flag (like TNG.debug) that you set to true to trigger the behavior.

  2. Once this mode is on, TNG would fire an event every time a hook is called, or some other thing alters one of the internal state contexts, such as an effect or cleanup running, or a state-slot updater running, etc. The event would include references to the parent Articulated Function instance, which hook, what kind of event it was, and any relevant provided values.

    The idea behind this is that you could audit a hook, including basically knowing the internal state of its hooks-context by replaying all these events. This would allow you to easily create verification tests to ensure your hooks are doing what they're supposed to be doing.

  3. It also would be helpful if there was a way to provide a list of these events to an Articulated Function and have it preload its context state. This lets you basically re-create a specific hooks context at will. That makes creating tests even more powerful.

    What I'm thinking is, this list of events could be an optional argument passed to an Articulated Function's reset(..) method.

So... thoughts?

getify commented 5 years ago

Now I'm thinking this shouldn't be a debug mode or optional at all... but that each Articulated Function would always emit an event any time any TNG-hook context changed. That could still be used for debugging and testing, but it's also useful to allow "lifecycle management" behavior (like React) to be built on top of TNG.

For example:

function hitCounter() {
   var [count,updateCount] = useState(0);

   useEffect(function onInit(){
      theBtn.addEventListener("click",function onClick(){ updateCount(x => x + 1); },false);
   },[]);

   useEffect(function onRender(){
      theBtn.value = count;
   },[count]);
}

hitCounter = TNG(hitCounter);

hitCounter.on("state-change",function onStateChange(artFn,hookIdx,oldValue,newValue){
   // re-render "component"
   artFn();  // aka "hitCounter()"
});