Refs and the Component Lifecycle
Calling Components and Elements Directly
Many times, one needs to directly call the methods of a component or HTML element. This can be accomplished by using the special ref
prop which exists on all components and elements, and works in much the same way as React refs do.
const elementRef = FSComponent.createRef<HTMLDivElement>();
const element = <div ref={elementRef}>Texty Goodness</div>;
FSComponent.render(element, document.getElementById('TextyContainer'));
elementRef.instance.classList.add('blink-red');
By using the special ref
prop, the element or component will be assigned to the instance
property of that passed-in ref after (and only after) the element is rendered.
A component or element's ref
will not be assigned until the element is rendered. If the instance
property is accessed before it has been assigned, an error will be thrown. You can instead use getOrDefault()
if you would like to get either the instance or undefined
. This method will not throw an error, and is therefore a good choice in areas where you don't know if rendering will yet be complete and would like to check on your own.
Lifecycle Methods Available on DisplayComponent
Also like React, FSComponent components have a few lifecycle methods which can be used to run code at specific times in the rendering cycle of a component.
constructor()
In FSComponent, component constructors are called as soon as the JSX elements are created, prior to starting the render cycle. Components are created from the bottom of the tree up.
constructor(props: TextyComponentProps) {
super(props);
console.log('Getting constructed...');
}
onBeforeRender()
The onBeforeRender()
method is called on a component immediately before the component's render()
method is called. This can be good for code that doesn't really fit into a normal constructor but needs to run before the component's rendering starts.
public onBeforeRender(): void {
super.onBeforeRender();
console.log('Just before rendering.');
}
onAfterRender()
The onAfterRender()
method is called on a component when the entire tree underneath it and its own render()
method have finished. Any code called from here, and after, is guaranteed to have access to any component or element refs, since they will all have been rendered. This method also has access to the virtual DOM node that resulted from its rendering, which is useful for a number of virtual DOM inspection purposes.
public onAfterRender(node: VNode): void {
super.onAfterRender(node);
console.log(`I have ${node.children.length} children.`);
}
It is good practice to call super
within the two lifecycle methods, just as one would for a constructor.
Adding Dynamic Styling to a Component With Ref and Lifecyle Methods
One of the most common ways of using both of these concepts in the framework is to change the styling of an element in a component dynamically due to changes in incoming data.
In MyComponent
, add a field for a ref to the display div to the top of the class:
private readonly elementRef = FSComponent.createRef<HTMLDivElement>();
And hook it up to the display div by adding the ref prop to that element in the render()
method:
<div ref={this.elementRef} class='my-component'>{this.indicatedAirspeed} IAS</div>
Then, subscribe to the indicatedAirspeed
value and use the following code to toggle a class on or off by adding the following to the lifecycle method onAfterRender()
:
public onAfterRender(node: VNode): void {
super.onAfterRender(node);
this.indicatedAirspeed.sub(airspeed => {
if (airspeed > 40) {
this.elementRef.instance.classList.add('alert');
} else {
this.elementRef.instance.classList.remove('alert');
}
});
}
We use the lifecycle method onAfterRender()
here because we are accessing a ref instance, which is guaranteed to be available when and after onAfterRender()
is called.
Finally, we can add some styling to this alert
class in our MyComponent.css
:
.alert {
color: white;
background-color: red;
}
Upon rebuild/resync, we should now see the styling of our airspeed value change when it is above 40 knots.