Component
Function and Class Components
The easiest way to define a component is to write a JavaScript function. The component can also be written as an ES6 class and extends the class Component
from Costro
. This offers more features which you will discover below. These can be imported from other files.
- Function Component
- Class Component
function Home(props) {
return <h2>Hello, {props.name}</h2>;
}
import { Component } from 'costro';
class Home extends Component {
render() {
return <h2>Hello, {this.props.name}</h2>;
}
}
Import `Component` with CDN links
Component
is exposed in the global variable window.Costro
.
class Home extends Costro.Component {}
Transform a Function to a Class
You can transform a function component to a class component with the following steps:
- Create an ES6 class with the same name, that extends
Component
. - Add a single method
render()
. - Move the content of the function into the
render()
method. - Replace
props
withthis.props
in therender()
content.
Lifecycle hooks
Lifecycle hooks are available on Class Components only.
We can declare special methods on the component class to run some code when a component is rendered or destroyed.
Try it on CodeSandbox.
Before render
The beforeRender()
method runs before the component output has been rendered to the DOM.
class Home extends Component {
beforeRender() {
// The component is not yet rendered to the DOM
}
render() {
return <h2>Home</h2>;
}
}
The beforeRender()
method can be asynchronous to get data before rendering the component. This will delay the execution of the render method.
After render
The afterRender()
method runs after the component output has been rendered to the DOM.
class Home extends Component {
render() {
return <h2>Home</h2>;
}
afterRender() {
// The component is rendered to the DOM
}
}
Access to the component's DOM must be done during the afterRender
hook.
Before destroy
The beforeDestroy()
method runs before the component has been removed to the DOM.
class Home extends Component {
beforeDestroy() {
// The component is not yet removed from the DOM
}
render() {
return <h2>Home</h2>;
}
}
After destroy
The afterDestroy()
method runs after the component has been removed to the DOM.
class Home extends Component {
render() {
return <h2>Home</h2>;
}
afterDestroy() {
// The component is removed from the DOM
}
}
Props
Props are inputs accepted by components and injected from the route.
The function component accepts a single props
object argument with data as a parameter. The class component has the same principle except that the props
are exposed in the context of the class with this.props
.
- Function Component
- Class Component
function Home(props) {
return `<h2>Hello, ${props.name}</h2>`;
}
class Home extends Component {
render() {
return `<h2>Hello, ${this.props.name}</h2>`;
}
}
If you implement the constructor()
function on the class component, you should call super(props)
before any other statement. Otherwise, props will not be available.
Hello, John Doe
Try it on CodeSandbox.
Nested components
Components can be nested and their props are automatically injected into the child component.
class Person extends Component {
render() {
return <h2>Hello, {this.props.name}</h2>;
}
}
class Home extends Component {
render() {
return <Person name="John Doe" />;
}
}
Hello, John Doe
State changes
You should manually update the DOM on state changes. Making carefully crafted manual updates is much faster than using a virtual DOM with diff algorithms (and also less magic). Lifecycle hooks can be useful in making these updates at the right time.
The following examples show how to update the DOM when the state changes.
- Event handling
- Nested component
Updates the #counter
element after each click.
class Counter extends Component {
constructor(props) {
super(props);
this.counter = 0;
this.handleClick = this.handleClick.bind(this);
}
render() {
return (
<button onClick={this.handleClick}>
Clicks: <span id="counter">{this.counter}</span>
</button>
);
}
handleClick() {
this.counter++;
document.getElementById('counter').textContent = this.counter;
}
}
Try it on CodeSandbox.
Updates the nested Clock
component with new props every second.
function Clock(props) {
return <span id="time">{props.time.toLocaleTimeString()}</span>;
}
class Counter extends Component {
render() {
return (
<>
It is, <Clock time={new Date()} />.
</>
);
}
afterRender() {
this.timer = setInterval(() => this.updateTime(), 1000);
}
updateTime() {
document.getElementById('time').replaceWith(<Clock time={new Date()} />);
}
beforeDestroy() {
clearInterval(this.timer);
}
}
Try it on CodeSandbox.
Route data
The component class exposes the route
data as a class property.
Signature
type route = {
path: string
params: {
[key: string]: string
};
};
Returns
Current path in URL and list of dynamic segments with their values.
Example
class Person extends Component {
render() {
return <h2>Person ID: {this.route.params.id}</h2>;
}
}
The above example with the route path /person/:id
will expose the following data in the this.route
object.
{
"path": "/person/42",
"params": {
"id": 42
}
}
Try it on CodeSandbox.