Fastboard's UI is well decoupled from the core logic, which enables you to easily create your own UI through the API provided by Fastboard Core.
UI is nothing but some components reflecting the value of the state. Take the following React component for example:
function App() {
let [count, setCount] = useState(0);
// ^ state
return <button onClick={() => setCount(count + 1)}>{count}</button>; // view (UI)
// ^ actions to modify state (not view!)
}
To make our state observable, Fastboard provides several values which can be observed through callbacks:
let app = await createFastboard({ ...config });
app.writable; // { value: true, subscribe/reaction, set? }
value
Get current value.
subscribe/reaction
Listens for changes in the value and the callback parameter is the new value.
The difference between the 2 methods is that subscribe
will execute the callback at once
while reaction
won't.
Returns a function to unsubscribe.
let dispose = app.writable.subscribe(value => {
console.log("writable:", value);
}); // writable: true
app.writable.reaction(value => {
console.log("writable2:", value);
}); // not print anything
app.writable.set(false); // writable: false, writable2: false
dispose();
app.writable.set(true); // writable2: true
set
(Maybe exist) Set the value. Note that this change may not be updated to value
immediately since we have to sync it.
We can make use of React Hooks to listen updates to these values:
import { useState, useEffect } from "react";
function useAppWritable(app) {
const [value, setValue] = useState(app.writable.value);
useEffect(() => app.writable.subscribe(setValue), [app]);
// The disposer returned by `subscribe` can just be passed into `useEffect`, so convenient.
return value;
}
We can make use of the Reactivity API of Vue3:
Warning: Some values in Fastboard are implemented in Proxy
, don't let them be wrapped again in Vue's data
or ref
, reactive
, use shallowRef
instead.
import { ref, readonly, computed, onUnmounted } from "vue";
function useAppWritable(app) {
const writable = ref(app.writable.value);
const dispose = app.writable.reaction(value => {
writable.value = value;
});
onUnmounted(dispose);
// Do not want users to do {{ writable = true }}
return readonly(writable);
// If you want to make the value writable, you can use `computed` to proxy it.
return computed({
get: () => writable.value,
set: value => {
app.writable.set(value);
// Important: do not call `writable.value = value` here,
// instead we should let that happen in the reaction callback.
},
});
}
Our interface is compatible with the Svelte Store API, so you can use it directly:
<script>
let writable = app.writable;
</script>
<div>{$writable ? 'you can control the whiteboard' : 'readonly'}</div>