0.0.23 • Published 9 days ago

mosa-js v0.0.23

Weekly downloads
-
License
MIT
Repository
github
Last release
9 days ago

Mosa (Monode's State API)

A unified format for reactivity to keep stuff consistent across Monode tools.

Set Up

First initialize Mosa for your platform. For example if you're using Solid JS you would do this:

import { initializeMosa } from "@monode/mosa";
import { mosaConfigForSolid } from "@monode/mosa/solid";

export { userProp, useFormula, doNow, doWatch } = initializeMosa(mosaConfigForSolid);

Initializing Mosa returns four main functions useProp, useFormula, doNow, and doWatch.

useProp

Creates a basic, reactive value that can be read by using myProp.value, and written to using myProp.value = newValue.

function MyComponent() {
  const myProp = useProp(0);

  return (
      {/* Assigning to `myProp.value` will cause the text below to automatically re-render. */}
    <Button onClick={() => myProp.value++}>
      {/* Because we read `myProp.value` this will automatically re-render when myProp changes. */}
      You've pressed the button {myProp.value} times.
    </Button>
  );
}

If you're curious, here is the actual source code for useProp.

export function useProp<GetType, SetType = GetType>(
  initValue: GetType | SetType,
): Prop<GetType, SetType> {
  const { get, set } = mosaConfig.createSignal(initValue);
  // We prefer to the `.value` syntax to Solid's function syntax, hence why we do this.
  return {
    // Reads the value, and triggers a re-render when it changes.
    get value(): Unionize<GetType> {
      return get() as Unionize<GetType>;
    },
    // Updates the value and notifies all watchers.
    set value(newValue: Unionize<SetType>) {
      set(newValue as any);
    },
  } as any;
}

useFormula

Creates a reactive value that is derived from other reactive values and can be accessed via myFormula.value. It's like a computed property in Vue or SolidJS.

function MyComponent(props: { firstName: string; lastName: string }) {
  const myFormula = useFormula(() => `${props.firstName} ${props.lastName}`);
  // Will re-render if firstName or lastName changes.
  return <Txt>{myFormula.value}</Txt>;
}

Can also be be called with a second function to create a read/write formula. Note, the write type is assumed to be the same as the read type, but you can override it if you need to.

const myProp = useProp<number | null>(null);
// In this example we use `useFormula` to create a non-null version of `myProp`.
const myFormula = useFormula(
  () => myProp ?? 0,
  // Can be written to.
  (newValue: number) => (myProp.value = newValue),
);

If you're curious, here is the actual source code for useFormula.

export function useFormula<
  GetType,
  Setter extends ((value: any) => any) | undefined =
    | ((value: GetType) => any)
    | undefined,
>(
  compute: () => GetType,
  /** Optional setter function */
  set?: Setter,
): ReadonlyProp<GetType> &
  (undefined extends Setter
    ? {}
    : Setter extends (...args: any[]) => any
    ? WriteonlyProp<Parameters<Setter>[0]>
    : {}) {
  const { get } = mosaConfig.createComputed(compute);
  return {
    _isSig: true,
    get value(): GetType {
      return get();
    },
    // The value can't be set on readonly formulas.
    set value(newValue) {
      set?.(newValue);
    },
  } as any;
}

doNow

Just runs the provided function immediately and returns the result. It just helps corral code.

// `myNum` will equal 42
const myNum = doNow(() => 42);

If you're curious, here is the actual source code for doNow.

export function doNow<T>(func: () => T): T {
  return func();
}

doWatch

Runs the provided function immediately and then again whenever any of the reactive values it reads from change.

const myProp = useProp(0);

// Immediately logs "myProp: 0"
doWatch(() => {
  console.log("myProp: ", myProp.value);
});

// Logs "myProp: 1" when myProp changes.
myProp.value = 1;

You may also provide an on option to control exactly which props to watch.

const myProp = useProp(0);
const myOtherProp = useProp(0);

// Immediately logs "myProp: 0"
doWatch(
  () => {
    console.log("myProp: ", myProp.value);
  },
  { on: [myProp] },
);

// Logs "myProp: 1" when myProp changes.
myProp.value = 1;

// Does not log anything when myOtherProp changes.
myOtherProp.value = 1;

If you're curious, here is the actual source code for doWatch.

export function doWatch(
  func: () => void,
  options?: Partial<{
    on: ReadonlyProp<any>[];
  }>,
) {
  this.exists(options?.on)
    ? mosaConfig.createManualEffect({
        on: options.on,
        do: func,
      })
    : mosaConfig.createAutoEffect(func);
}
0.0.23

9 days ago

0.0.22

1 month ago