atomicojs / atomico

Atomico a micro-library for creating webcomponents using only functions, hooks and virtual-dom.
https://atomicojs.dev
MIT License
1.16k stars 43 forks source link

Run method in constructor #25

Closed ManzDev closed 3 years ago

ManzDev commented 4 years ago

Hello,

I want run a "user-custom method" on native WebComponent constructor lifecycle. What is the best way to do this with atomico?

My problem is that I need extract content of WebComponent markup before mount.

I have the same doubt for events like connectedCallback, disconnectedCallback or adoptedCallback.

Great work, I like Atomico!

UpperCod commented 4 years ago

Hi, the Atomico render cycle is released only after mount, this with the aim of correctly synchronizing properties (reflecting default values) or events (allowing a synchronization between component indifferent to the mounted order).

You can follow the component state through promises, eg:

let WebComponent = document.createElement("web-component");

await WebComponent.mounted // before render  == connectedCallback 

await WebComponent.rendered // after render

WebComponent.props1 = 10;
WebComponent.props2 = 20;
WebComponent.props3 = 30;

await WebComponent.rendered // after render 

await WebComponent.unmounted // disconnectedCallback

https://github.com/atomicojs/atomico/blob/master/src/core/element/element.js#L134-L160

you can comment on your need in more detail, for a better solution or improvement of Atomico... I have been thinking of associating the life cycle with an event, so as not to depend on a previous definition of the webComponent

ManzDev commented 4 years ago

First of all, sorry for my lack of knowledge. I'm new at hooks and maybe something is nonsense.

I'm trying to find a solution to "fallback" components + nice reuse:

  1. Empty web-component, resolve into fallback content (defined into webcomponent)
  2. Web-component with tags inside, resolve into clone this markup and style (from inside component). This solution is SEO-friendly and WC-friendly.

For example:

<web-component>
  <h2>Title</h2>
   <p>Content with <strong>markup</strong></p>
</web-component>

I want to get component's content before mount it, to reuse it inside.

I try this with slots, but use styles from light dom, and I want copy markup but apply styles from inside component. I think that clone content (from constructor), I can get it.

UpperCod commented 4 years ago

Thanks for your Issue, it has motivated me to generate this update at Atomico@0.17.0 that allows a better interaction with lightDom, eg:

This allows to homologize the behavior of the shadowDom, but it is recommended to use only in cases where the DOM comes from HTML, eg:

html

<web-component>
    <h2 slot="title">Title</h2>
    <p>Content with <strong>markup</strong></p>
</web-component>

JS

import { h, customElement, useMemo, useHost, useState } from "atomico@0.17.0";

const WebComponent = () => {
  // use Host allows to obtain the reference of the webcomponent
  // without the need for the first render
  let ref = useHost();

  let [state, setState] = useState(0);
  // using useMemo you can generate a map of the existing
  // nodes before the render replaces them
  let { Title } = useMemo(() => {
    return {
      Title: ref.current.querySelector("[slot='title']")
    };
  }, []);

  return (
    <host>
      <strong>inside web-component</strong>, the example takes the existing node
      in the document to reuse it within the webcomponent like any other vnode.
      <br />
      <br />
      <strong>counter = {state}</strong>
      <Title
        onclick={() => {
          setState(state => state + 1);
        }}
        style={{ color: "red" }}
      />
      ...end
    </host>
  );
};

export default customElement(WebComponent);

Where :

https://webcomponents.dev/embed/h67bGeTp2qKdb26ZgmkU

subRender and LightDom.

You can manipulate the state of a node through the render function, eg

import { h, render, useHost } from "atomico";

function useFocusRender(callback, selector) {
  let ref = useHost();
  render(callback(), ref.current.querySelector(selector));
}

function WebComponent() {
  useFocusRender(
    () => (
      <host
        style={{ color: "red" }}
        onclick={() => {
          console.log("click!");
        }}
      ></host>
    ),
    "h2"
  );

  return <host></host>;
}

example

Atomico and shadowDom

::slotted() , It allows you to manipulate the style of a slot from inside the webComponent, but this does not help with the association of events. seo, currently the google robot should process the shadowDom without any problems since it is based on crhome 74, source.

I hope this is useful!