---
# System prepended metadata

title: Brainstorming ideas on Component declaration

---

# Brainstorming ideas on Component declaration

```typescript=
import { Fragment, h } from '@builder.io/qwik';

export const MyApp = () => <MouseDebuggerA />;

export const HelloWorld = qComponent(({ render }) => {
  render(() => <span>HelloWorld</span>);
});

// Ideas
// 1. We should get rid of QComponent, instead the state should be the reference.
// 2. remove QRecord and replace with simple QObject

export const useMousePosition = qEffect(({ listen, createState, handle }) => {
  createState(() => ({ x: 0, y: 0 }));

  listen(
    'document:mousemove',
    handle(({ state, event }) => {
      state.x = event.x;
      state.y = event.y;
    })
  );
});

// NOTES:
// 1. I like that the qComponent turns into a single closure which the developer can edit.
//    Tooling knows how to collapse it etc. Feels like a class without the class.
// 2. If devs want to break up the code they can do so out into the closure
// 3. PROBLEM: If fn gets extracted (say handler) into qComponet top level when the tooling
//    pulls it out it creates an issue as those functions can't call other functions in the closure
export const MouseDebuggerA = qComponent<{}, { count: number; mouse: { x: number; y: number } }>(
  ({ createState, render, handle }) => {
    const increment1 = handle(({ state }) => state.count++);

    createState(() => ({
      mouse: useMousePosition(),
      count: 0,
    }));

    render(({ state }) => (
      <>
        Mouse: ({state.mouse.x}, {state.mouse.y})<button on:click={increment1}>+</button>
      </>
    ));
  }
);

// NOTES:
// 1. because functions are already top level, it is easy to move them by the tooling.
export const MouseDebuggerB = qComponentB<{}, { count: number; mouse: { x: number; y: number } }>({
  createState: qrl(() => ({
    mouse: useMousePosition(),
    count: 0,
  })),

  render: qrl(({ state }) => (
    <>
      Mouse: ({state.mouse.x}, {state.mouse.y})<button on:click={increment1}>+</button>
    </>
  )),
});

const increment1 = qrlHandler<typeof MouseDebuggerB>(({ state }) => state.count++);

////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////

interface QComponent<PROPS = {}, STATE = {}, REF = {}> {
  __props__: PROPS;
  __state__: STATE;
  __ref__: REF;
  (props: any): any;
}

interface Qrl<T> {
  __brand__: T;
}
function use(element: HTMLElement, ref: any) {
  console.log(element, ref);
}
function qrl<T>(fn: T): Qrl<T> {
  console.log(fn);
  return null!;
}

function qrlHandler<COMP extends { __props__: any; __state__: any; __ref__: any }>(
  fn: ({ state }: { state: StateOf<COMP> }) => void
): Qrl<({ state }: { state: StateOf<COMP> }) => void> {
  console.log(fn);
  return null!;
}

export type StateOf<COMP extends { __props__: any; __state__: any; __ref__: any }> = COMP extends {
  __props__: any;
  __state__: infer STATE;
  __ref__: any;
}
  ? STATE
  : never;

function qComponent<PROPS = {}, STATE = {}, REF = {}>(
  fn: ({
    createState,
    render,
    handle,
  }: {
    createState: (fn: ({ element }: { element: HTMLElement }) => STATE) => void;
    render: (fn: ({ state }: { state: STATE }) => any) => void;
    handle: (fn: ({ state }: { state: STATE }) => void) => Qrl<any>;
  }) => void
): {
  __props__: PROPS;
  __state__: STATE;
  __ref__: REF;
  (props: any): any;
} {
  console.log(fn);
  return null!;
}

function qComponentB<PROPS = {}, STATE = {}, REF = {}>(def: {
  createState?: Qrl<({ element }: { element: HTMLElement }) => STATE>;
  render?: Qrl<({ state }: { state: STATE }) => any>;
}): {
  __props__: PROPS;
  __state__: STATE;
  __ref__: REF;
  (props: any): any;
} {
  console.log(def);
  return null!;
}

```