References
Last updated
Last updated
Note: These docs were adopted from the original docs
Usually, when creating a node, we want to store a reference to it, so we can animate it later. One way to do that is by assigning it to a variable first, and then adding it to the scene:
info
If you're used to libraries such as React, the above example may seem strange. In Motion Canvas, the JSX components immediately create and return an instance of the given class. It's completely valid to store it as a reference and use it throughout the animation.
But this approach doesn't scale well. The more nodes we add, the harder it gets to see the overall structure of our scene. Consider the following example:
And now compare it to a version that doesn't store any references:
If you find the latter example more readable, this guide is for you.
Each node in Motion Canvas has a property called ref
that allows you to create a reference to said node. It accepts a callback that will be invoked right after the node has been created, with the first argument being the newly created instance.
With this in mind, we can rewrite the initial example as:
Using the ref
property in this way is not really practical, and we wouldn't recommend it. But it's crucial to understand how it works because all the upcoming methods use this property as a base.
The preferred way of using the ref
property is in conjunction with the createRef()
function. Continuing with our example, we can rewrite it as:
Notice that circle
is no longer just a variable that points to our circle. Instead, it's a signal-like function that can be used to access it. Invoking it without any arguments (circle()
) returns our instance.
Going back to the example with the more complex scene, we can now rewrite it as:
Another common use case of the ref
property is to assign the newly created instance to a property of some object. In the following example, we assign our circle to circle.instance
(We'll talk about why this may be useful in a bit):
We can use the makeRef()
function to simplify this process:
makeRef()
can be particularly useful when we create an array of nodes and want to grab references to all of them:
In JavaScript, arrays are objects whose properties are their indices. So makeRef(circles, index)
will set the nth element of our array to the created circle. As a result, we end up with an array of size 10
filled with circles that we can use to animate all of them.
This time we don't specify the index. Whenever we pass the circles
array to the ref
property, the newly created circle will be appended to our array.
tip
makeRef()
can also be used to return more than one reference from a custom function component:
In this example, we define a function component called Label
consisting of a rectangle with some text inside. When using the component, we use the refs
property to pass the label
object created by us. makeRef()
is then used to fill this object with all the necessary references.
The returned object is a map that can store however many references we need. In the above example, we assign three Txt
references under the keys a
, b
, and c
. Simply accessing a property of the map, like labels.a
will create a reference for us. The names of the properties are arbitrary and can be anything we want.
Later on, we can retrieve the references using the same keys:
To check if a reference exists, we can use the in
operator. This will avoid creating a reference:
Looking at the previous example, you may notice that we had to define the refs
type twice. First in the Label
declaration and then again when creating the label
object:
We can use makeRefs()
to eliminate this redundancy. It can extract the type from the Label
declaration and create an empty object matching it:
You can also use the helper function to achieve the same result:
Check out to see how an array of references can be used to orchestrate animations.
As the scene grows in complexity, declaring a reference for each node can become tedious. The helper function lets us group references together based on the type of the node:
The returned object comes with a mapRefs
method that lets us map over all references in the map. It's similar to the function: