This update introduces significant improvements to the way models and views interact. We focused on automatically updating the view side whenever the model changes, simplifying the overall workflow. Additionally, new features have been added to enhance the developer experience, such as dynamically connecting to new sessions and accessing a list of connected views.
To see these changes in action, check out the following example repositories:
Updating existing code
Model side
- Your model should inherit from
ReactModel
Update your existing models to inherit from the ReactModel
class.
The ReactModel
class is a new base class introduced in this update, which allows the view side to be automatically updated whenever the model changes.
import { ReactModel } from "@croquet/react";
class CounterModel extends ReactModel {
// Your model logic goes here
}
- No need to publish output events
If your model events were exclusively published to update the view side, you may drop them. The ReactModel
class automatically handles the updates to the view side.
class CounterModel extends ReactModel {
resetCounter() {
this.count = 0;
// Remove the line below:
// this.publish(this.id, "count");
}
}
- Override the
handleViewJoin
andhandleViewExit
methods
Subscribing directly to view-join
and view-exit
events is not supported in this version.
Instead, you should override the handleViewJoin
and handleViewExit
methods.
class YourModel extends ReactModel {
init(option) {
super.init(option)
// Remove the lines below:
// this.subscribe(this.id, "view-join", this.handleViewJoin);
// this.subscribe(this.id, "view-exit", this.handleViewExit);
}
// Override these methods instead
handleViewJoin(viewId) { /* ... */ }
handleViewExit(viewId) { /* ... */ }
}
View side
- Use the
useReactModelRoot
hook, instead ofuseModelRoot
In your view side, replace the useModelRoot
hook with the new useReactModelRoot
hook.
This new hook returns a stateful object that will be automatically updated whenever the model changes.
import { useReactModelRoot } from "@croquet/react";
function CounterView() {
const model = useReactModelRoot<CounterModel>();
}
- Remove state that was used to represent the model data
Since useReactModelRoot
returns a stateful object, you don't need to create a React state to represent the model.
function CounterView() {
// Remove the line below:
// const [count, setCount] = useState(model.count);
const count = model.count;
}
- You don't need to subscribe to model events anymore
The useReactModelRoot
hook ensures that your view components always have access to the latest state of the model, without the need for explicit event subscriptions or manual updates.
However, if your logic requires you to subscribe to specific events, this behavior is still supported.
function CounterView() {
// Remove the line below
// useSubscribe(model.id, "count", () => setCount(model.count), []);
}
- Call the model handlers instead of using
usePublish
The object returned by useReactModelRoot
has the same interface as the root model of your application, so you can call the model event handlers directly.
Those functions publish the event that will be handled by the respective function, but it feels like you are calling the model methods directly, which is nice!
Nonetheless, using the usePublish
hook is still supported.
function CounterView() {
// Remove the line below
// const publishReset = usePublish(() => [model.id, "reset"], []);
// Make sure the DOM event is not passed to the method
return (
<div onClick={(_) => model.reset()}>
{model.count}
</div>
);
}
New features
- Dynamically connecting to a new session
If you ever need to change the session your application is connected to, you can simply use the function returned by the useChangeSession
hook.
This will cause the <CroquetRoot/>
component to connect to leave the current session and connect to a new one.
import { useChangeSession } from '@croquet/react'
export default function YourComponent() {
const changeSession = useChangeSession()
const handleConnectNewSession = (newSessionName, newSessionPassword) {
changeSession({ name: s.name, password: s.password })
}
}
- Access all the connected views with the
useConnectedViews
hook
We also introcuded a new hook useConnectedViews
that gives you access to a list of views that are connected to the same session.
import { useConnectedViews } from '@croquet/react'
export default function YourComponent() {
const { views, viewCount } = useConnectedViews()
return (
<>
<p>Listing all {viewCount} views:</p>
<ul>{ views.map((v) => <li>{v}</li>) }</ul>
</>
)
}
We made this feature opt-in, so you will need to configure it in your <CroquetRoot/>
component
export default function Wrapper() {
return (
<CroquetRoot
sessionParams={{
// ... other configuration
options: { trackViews: true }
}}
>
<App/>
</CroquetRoot>
)
}