4.0.9 • Published 3 years ago

r9x_js v4.0.9

Weekly downloads
20
License
MIT
Repository
github
Last release
3 years ago

R9X

R9x é uma estrutura para criação de componentes reativos através de funções fábricas.

Documentação completa: r9x_io

Componentes

Criar um componente é muito fácil. Veja o exemplo abaixo:

const appHello = () => {

    const state = {
        title:'Hello World!'
    }

    const template = ({props, state}) => {
        return /*html*/`<h1 class="title">${state.title}</h1>`
    }


    const styles = () => {
        return /*css*/`
            app-hello .title {
                color: blue;
                text-align:center;
            }
        `
    }

    return {
        state,
        template,
        styles
    }
}

export { appHello }

Dentro da função fábrica acima declaramos o state o template e os estilos css do componente appHello. Em seguida os retornamos dentro de um objeto literal.

    return {
        state,
        template,
        styles
    }

Embora declarados dentro do escopo da função fábrica, o template, os estilos e o próprio state do componente, poderiam rer importados de outros arquivos. Veja abaixo:

import helloTemplate from 'another/place'
import helloStyles from 'anhother/place'
import helloState from 'another/place'

const appHello = () => {

    const state = helloState
    const template = helloTemplate
    const styles = helloStyles

    return {
        state,
        template,
        styles
    }
}

export { appHello }

Ainda poderia ficar mais simples:

import template from 'another/place'
import styles from 'anhother/place'
import state from 'another/place'

const appHello = () => {

    return {
        state,
        template,
        styles
    }
}

export { appHello }

Comoponentes interativos

É possível criar interatividade nos componentes através de eventos e metodos simples. Veja abaixo:

import template from 'another/place'
import styles from 'anhother/place'
import state from 'another/place'

const appHello = () => {

    const events = ({on, query, methods}) => ({

        onClickTitle: () => {
            const titleElement = query('.title')
            on('click', [titleElement], ({target}) => methods.logger(target))
        }

    })

    const methods = ({props, state}) => ({

        logger: (...params) => console.log( ...params )

    })

    return {
        state,
        template,
        styles,
        events,
        methods
    }
}

export { appHello }

Os recursos introduzidos acima garantem que ao clicar no título, o elemento alvo do clique seja logado no console.

hooks

Ainda é possível definir comportamentos automáticos através dos hooks.

Atualmente existes 4 hooks observáveis:

  • beforeOnInit - executado apenas uma vez antes do componente ser inicializado
  • afterOnInit - executado apenas uma vez depois do componente ser inicializado
  • beforeOnRender - executado antes da renderização sempre que o componente renderiza o template
  • afterOnRender - executado após a renderização sempre que o componente é renderizado.

Veja o exemplo abaixo:

import template from 'another/place'
import styles from 'anhother/place'
import state from 'another/place'

const appHello = () => {


    const hooks = ({methods}) => ({

        beforeOnInit () {
            methods.logger('antes de appHello ser inicializado')
        },
        afterOnInit () {
            methods.logger('depois de appHello ser inicializado')
        },
        beforeOnRender () {
            methods.logger('antes de appHello ser renderizado')
        },
        afterOnRender () {
            methods.logger('depois de appHello ser renderizado')
        },

    })

    return {
        state,
        template,
        styles,
        hooks
    }
}

export { appHello }

O recurso incluído acima exibiria no console as mensagens dispostas em beforeOnInit e afterOnInit apenas uma vez, enquanto exibiria multiplas vezes as mensagens em beforeOnRender e afterOnRender.

Directives

As diretivas em r9x são apenas funções simples que manipulam os fragmentos do DOM presentes no componente com base no estado e nos eventos do próprio componente.

Veja o exemplo abaixo:

import template from 'another/place'
import styles from 'anhother/place'
import state from 'another/place'

const appHello = () => {

    const events = ({on, query, directives}) => ({

        onClickTitle: () => {
            const input = query('#name')
            on('keyup', [input], ({target}) => directives.changeColor(target))
        }

    })

    const directives = ({query}) => ({

        changeColor: (target) => {
            
            if(!target || !target.value) return

            target.value.length <= 3 ? 
                target.style.color = 'red' : 
                target.style.color = 'blue'
        }

    })

    return {
        state,
        template,
        styles,
        events,
        directives
    }
}

export { appHello }

No exemplo acima, sempre que o evento onkeyup ocorrer, a diretiva changeColor será executada alterando o aspecto visual do input com base na quantidade de caracteres encontrada na propriedade value do mesmo.

Reactive State

Fazer os componentes criados com R9X reajam a mudanças no estado também é algo bem simples e atualmente existem 2 estratégias:

1 . Scoped State - Nessa estratégia o componente possui um estado local que só reflete os efeitos colaterais de alteração dos dados para o próprio componente.

2 . Stored State - Nessa estratégia os efeitos colaterais são desencadeados em todos os componentes inscritos na store de dados.

Scoped State

const appHello = () => {

    const state = {
        title: 'Hello World!'
    }

    const events = ({on, query, methods}) => ({

        onClickTitle: () => {
            const titleElement = query('.title')
            on('click', [titleElement], methods.changeTitle)
        }

    })

    const methods = ({props, state}) => ({

        changeTitle: () => state.set({title: 'Hello crazy world!'})

    })

    return {
        state,
        events,
        methods
    }
}

export { appHello }

Observe que o evento de click no elemento de título do componente executará a função changeTitle que modificará o estado atribuindo o valor Hello crazy world! a propriedade title do state. Isso fará com que o template do componente seja renderizado exibindo o novo título.

Stored State

import store from 'anoter/place/store`'

const appHello = () => {

    const state = {
        title: store.get().title
    }

    const hooks = ({methods}) => ({

        beforeOnInit () {
            store.subscribe((data) => state.set(data)
        }

    })

    const events = ({on, query, methods}) => ({

        onClickTitle: () => {
            const titleElement = query('.title')
            on('click', [titleElement], methods.changeTitle)
        }

    })

    const methods = ({props, state}) => ({

        changeTitle: () => store.update({title:'Another title crazy world!'}))

    })

    return {
        state,
        hooks
        events,
        methods
    }
}

export { appHello }

Note que importamos a store de dados e que a propriedade title do state foi inicializada com o valor equivalente presente na store.

    const state = {
        title: store.get().title
    }

Depois adicionamos um observador à store para atualizar o state local assim que a store for modificada.

    const hooks = ({methods}) => ({

        beforeOnInit () {
            store.subscribe((data) => state.set(data)
        }

    })

Por fim, o método changeTitle atualiza a store através da função update disponibilizada pela própria store para alterar seus dados e notificar os observadores sobre as modificações.

    const methods = ({props, state}) => ({

        changeTitle: () => store.update({title:'Another title crazy world!'}))

    })

Dessa forma, todo e qualquer componente observando a store receberá os novos dados e uma notificação de que os dados presentes na store foram alterados e poderão decidir programaticamente sobre qual comportamento reativo adotar.

Reactive properties

Propriedades reativas devem ser usadas para passar informação para componentes filhos.

Essas propriedaes são obaservadas assim como o state e a cada alteração geram um efeito colateral observado pelo componente que culminará em uma nova renderização do template do mesmo.

As propriedades reativas também estão acessíveis ao template e aos metodos do componente.

appName.component.js

const appName = () => {

    const state = {}

    const template = ({props, state}) => /*html*/`
        <p>${props.name}</p>
    `

    return {
        state,
        template,
    }
}

export { appHello }

appHello.component.js

import appName from 'anhother/place/appName.component'

const appHello = () => {

    const state = {
        title:'Hello World!',
        name: 'Alfred',
    }

    const children = () => ({
        appName
    })

    const template = ({props, state}) => /*html*/`
        <h1 class="title">${state.title}</h1>
        <app-name data-props="{'name':`${state.name}`}"></app-name>
        `

    return {
        state,
        template,
        children,
    }
}

export { appHello }

O componente appName está configurado para receber por propriedade o valor de name e exibir dentro da tag p do template.

Observe que appName foi importado e anexado como filho de appHello através da função children. Veja também, que o componente appHello passa o valor (name) esperado em appName para o mesmo através da propriedade html data-props presente na tag do componente filho.

4.0.9

3 years ago

4.0.8

3 years ago

4.0.7

3 years ago

4.0.5

3 years ago

4.0.4

3 years ago

4.0.6

3 years ago

4.0.3

3 years ago

4.0.2

3 years ago

4.0.1

3 years ago

4.0.0

3 years ago

3.0.3

3 years ago

3.0.2

3 years ago

3.0.1

3 years ago

3.0.0

3 years ago

2.0.3

4 years ago

2.0.4

4 years ago

2.0.2

4 years ago

2.0.1

4 years ago

2.0.0

4 years ago

1.0.11

4 years ago

1.0.12

4 years ago

1.0.10

4 years ago

1.0.9

4 years ago

1.0.8

4 years ago

1.0.7

4 years ago

1.0.6

4 years ago

1.0.5

4 years ago

1.0.1

4 years ago

1.0.4

4 years ago

1.0.0

4 years ago