wbijker / spwa-php

A Server-Powered Web Applications (SPWA) framework using PHP.
0 stars 0 forks source link

Component based design #8

Open wbijker opened 9 months ago

wbijker commented 9 months ago

Create two base classes. ViewComponent - a component that does not carry any state and it basically a function that will return a HtmlTemplateNode; StateComponent - a component that can dynamically read and write state.

wbijker commented 3 months ago

Design with lifecycle events

<?php

class Counter extends Component {

    counter = 0;

    function buttonClicked() {
        $this->counter++;
    }

    override function saveState(): array {
        // run after each action performed on the page
        // default implementation is to persist all members of this page
    }

    override function restoreState($saved: array) {
        // run just before any action on the page
        // does not run on the first render 
        // default restore all members of this page
    }

    override function initialize() {
        // run on every render before anything
        $this->counter = intVal($this->request->query("counter", 0));
    }

    overide function created() {
        // run on the first render of the page
    }

    overide function destroyed() {
        // after this component has been removed 
    }

    override function render(): HtmlResult {
        // use the functional compositional way to create html

        return div(
            new HtmlAttr("v-app", {"selectIndex: 0"}),
            class("mx-auto bg-gray-100"),
            button(
                text("Click me"),
                onClick($this->buttonClicked)
            ),
            span(
                show($this->visible),
                new HtmlAttr("v-show", "selectIndex == 1"),
                text("The current counter is ".$this->counter)
            ),
            button(
                new HtmlAttr("@click", "selectedIndex = 1")
                text("Toggle")
            )
        )
    }

}

function show($condition): HtmlAttr {
    return class($condition ? "block" : "none");
}

?>

register CounterPage in entry point (routes, controllers)
events: state, event cycles
handle events with parameters 

JS invoke phase 2
events can be member functions, but also can invoke JS functions. 
each component can also skip some JS, to perform JS clientside functions.

$diff = diff($old, $new);
render $diff to fontend to apply the changes. 

render multiple instances of Components.

<?php

class App extends Component {

    private $counter1 = new Counter();
    private $counter2 = new Counter();

    function setBoth() {
        // inperative handler
        $counter1->set(12);
        $counter2->set(12);
    }

    override function render(): HtmlResult {

        return div(
            class("h-screen w-full bg-red-200"),

            button(
                text("Set both counters"),
                onClick(&$this->setBoth)
            ),

            div(
                $counter1,
                $counter2
            )        
        )
    }
}

renderApp(new App())