rikschennink / conditioner

๐Ÿ’†๐Ÿป Frizz free, context-aware, JavaScript modules

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Mounting class declarations

knynkwl opened this issue ยท comments

Hello, I love your library but I am having trouble getting some thing working.

I am using Barba.js as the PJAX library and ideally I would like to import modules that are on the page, call the init() method and on pageLeave call the detroy() method on the module.

Here is what I have so far:

// This is loaded by Barba.js
export class Components {
    constructor() {
        conditioner.addPlugin({
            moduleSetName: name => `./${name}/index.js`,
            moduleGetConstructor: module => module.default,
            moduleImport: name => import(/* webpackMode: "lazy" */ `${name}`)
        });
    }

   onPageEnter(DOM) {        
        // lets go!
        this.hydrate = conditioner.hydrate(DOM);
    }

    onPageLeave() {
      // Need to destroy the loaded components, unless the are on the new page, in which case I need to reinit them with the new el
    }
}

Is there a way to call a Class because when I do it gives me an error saying I can't call it as a function?

export default ExampleModule {
    constructor() { }

    init(slider) {
        // Init Slider
    }

    destroy() {
        // Destroy Slider
    }
}

Some help on this would be amazing!!

commented

This is the default set up.

export default (slider) => {
    // Init Slider

    return () => {
        // Destroy slider
    }
}

You could do this:

class ExampleModule {
    constructor() {
        this.init();
    }

    init(slider) {
        // Init Slider
    }

    destroy() {
        // Destroy Slider
    }
}

export default (slider) => {
    // Init Slider
    const _myModule = new ExampleModule();

    return () => {
        // Destroy slider
        _myModule.destroy();
    }
}

Or override the moduleGetConstructor and moduleGetDestructor hooks.

@rikschennink Thanks for that.

How would I call the destroy() / init() method on pageleave/enter? I don't see any example of that in the docs.

commented

The hydrate method returns an array of modules. You can call destroy on each module when the page is unloaded.

Sorry for the back and forth, and I appreciate you helping me out with this!

on init I do:

init(){
    this.hydrate = conditioner.hydrate(DOM);
}

then on destroy, this.hydrate returns an array of modules. do I have to loop over them all and call the destroy method for each?

Is there a way to check if these module are on the new page, without using the hydrate method again? I'm trying not to reimport the JS just reuse the module.

destroy() {
  console.log(this.hydrate);
  // returns [{module}, {module}, {module}]

   this.hydrate.forEach(module => {
       module.destroy()
    });
}

in the case above, the module.destroy() doesn't do anything

The destroy method returns an empty function. Where do I set that?

ฦ’ () {}

commented

Should use unmount instead => https://codepen.io/rikschennink/pen/bzzbJN?editors=1010

I'll look into this when I have some time

Okay thanks for the help.

Could you point me in the right direction with overriding the moduleGetConstructor and moduleGetDestructor hooks to accept a Class module?

Would love to not have to have to call this at the bottom of each module:

export default (element) => {
    const _myModule = new Slider();
    _myModule.init(element);

    return () => {
        _myModule.destroy(element)
    }
}
commented

I think something like this, you'd have to set some debug statements to be sure.

conditioner.addPlugin({

  moduleGetConstructor: module => {
    return new module.default();
  },

  moduleGetDestructor: instance => {
    instance.destroy();
  }
});

module returns undefined in moduleGetConstructor for some reason.

This is the class:

class ExampleModule {
   constructor() {}
   init() {}
   destroy() {}
}

export default ExampleModule;
commented

It took a couple tries but I got a working example: https://codepen.io/rikschennink/pen/wNOvJB?editors=1010

Nice, I had to update moduleGetConstructor to include .default(element) to get it working.

thanks for the help! I think it's working now ๐ŸŽ‰

moduleGetConstructor: (module) => {
   return (element) => {
       return new module.default(element);
   };
}
commented

Fantastic! :) If you want you can close the issue ๐Ÿ‘

Sorry I'm late to the party.

I wanted to share how I've been handling a similar situation with a "pjax" library of my own.

I have all my modules in a modules folder. There is an index.js file that configures conditioner and exports a hydrate and an unmount function that I call on every page transition. I looks a bit like this:

import * as conditioner from 'conditioner-core'

let boundModules = []

// Webpack
conditioner.addPlugin({
  moduleSetName: name => name,
  moduleGetConstructor: module => module.default,
  moduleImport: name => import(`./${name}`)
})

// other plugins here, removed for brevity

export function hydrate () {
  boundModules = conditioner.hydrate(document.documentElement)
}

export function unmount () {
  boundModules.forEach(x => x.unmount())
}

Thank you @rikschennink for such an amazing library.