Skip to content

Live Functions

About

Freestyle provides utilities to take any non-live function and make it live. This is done with invalidate and useCloudQuery.

Before reading this, make sure you understand the basics of Cloudstate.

How to use

  1. Write your regular @cloudstate class.

  2. Any time you’d want to trigger anything reliant on a function to re-run, you can write (invalidate(thatFunction)), where thatFunction is the function you want any thing reliant on it to re-run.

  3. In your frontend, wrap any useCloud methods you want to be live with useCloudQuery to make them live

Example

`

  1. Write your regular @cloudstate class.
    TodoList.ts
    import { cloudstate } from "freestyle-sh";
    @cloudstate
    export class TodoList {
    static id = "todoList";
    items: TodoItem[] = [];
    addItem(text: string) {
    this.items.push(new TodoItem(text));
    }
    getItems() {
    return this.items.map(item => item.getInfo());
    }
    }
    @cloudstate
    export class TodoItem {
    id = crypto.randomUUID();
    text: string;
    completed = false;
    constructor(text: string) {
    this.text = text;
    }
    toggle() {
    this.completed = !this.completed;
    }
    getInfo() {
    return {
    id: this.id,
    text: this.text,
    completed: this.completed
    };
    }
    }
  2. Any time you’d want to trigger anything reliant on a function to re-run, you can write (invalidate(thatFunction)), where thatFunction is the function you want any thing reliant on it to re-run.
    TodoList.ts
    import { cloudstate } from "freestyle-sh";
    @cloudstate
    export class TodoList {
    static id = "todoList";
    items: TodoItem[] = [];
    addItem(text: string) {
    this.items.push(new TodoItem(text));
    invalidate(useCloud("todoList").getItems);
    }
    getItems() {
    return this.items.map(item => item.getInfo());
    }
    }
    @cloudstate
    export class TodoItem {
    id = crypto.randomUUID();
    text: string;
    completed = false;
    constructor(text: string) {
    this.text = text;
    }
    toggle() {
    this.completed = !this.completed;
    invalidate(useCloud(this.id).getInfo);
    invalidate(useCloud("todoList").getItems);
    }
    getInfo() {
    return {
    id: this.id,
    text: this.text,
    completed: this.completed
    };
    }
    }
  3. In your frontend, wrap any useCloud methods you want to be live with useCloudQuery to make them live
    App.tsx
    import { useCloudQuery, useCloud } from "freestyle-sh/react";
    import { TodoList } from "./TodoList";
    export function App() {
    const todoList = useCloud<typeof TodoList>("todoList");
    const {data: items } = useCloudQuery(todoList.getItems);
    return (
    <div>
    <h1>Todo List</h1>
    <button onClick={() => todoList.addItem("New Item")}>Add Item</button>
    <ul>
    {items.map(item => (
    <li key={item.id}>
    <input type="checkbox" checked={item.completed} onChange={() => todoList.toggle(item.id)} />
    {item.text}
    </li>
    ))}
    </ul>
    </div>
    );
    }

Gotchas

  • Remember not to invalidate off this in a class, to invalidate functions used through useCloud, you must invalidate off the useCloud method itself.
  • Remember invalidating a function that another function relies on will not re-run the function that relies on it. You must invalidate the function that will be subscribed to by the useCloudQuery method.
  • useCloudQuery is great for live data, but not for server side rendering, it is best paired with a single useCloud call at the start for first render, and then useCloudQuery for live data.