Hey Stencil user! Are you using the official StencilJS Router and can't find how to detect route change events? Don't worry, my friend! You will find all the answers here.
So, is there an onRouteChange
event somewhere? Or something like router.subscribe
?
Nope. Its much simpler. Much much simpler, but for some reason, its not documented in the official Wiki (As of the time of writing), resulting in people using the ion-router
instead, where everything is very very well documented.
I myself had to port an application from Stencil Router to Ion router just because of this very reason, and it was a total pain.
But after some searching and experimenting, I figured it out (No not time travel, I ain't Tony Stark). And it was staring me in the face. It was that simple. Its built right into the very core of Stencil's architechture.
#Solution
So here's your typical Stencil component.
import { Component, Prop, h } from "@stencil/core";
@Component({
tag: "my-first-component",
})
export class MyComponent {
@Prop() name: string;
render() {
return <p>My name is {this.name}</p>;
}
}
This becomes
import { Component, Prop, h, Watch } from "@stencil/core";
import { LocationSegments, injectHistory } from "@stencil/router";
@Component({
tag: "my-first-component",
})
export class MyComponent {
@Prop() name: string;
/**
* Remember, this should be `location only`
*/
@Prop() location: LocationSegments;
/**
* Now watch for any changes to the location property
*/
@Watch("location") onRouteChange(newRoute, oldRoute) {
// Do some epic shit
// Like changing document title or
// Route animations. Its your choice.
}
render() {
return <p>My name is {this.name}</p>;
}
}
STOP!! It will still not work.
Yup this code will still not work. Let me explain why:
The important bit here is the location
prop. Think about it. Its a Prop. You pass a value to it. But here, nothing really is passing any value to our component here. Stencil certainly ain't.
So, the solution is to have something pass a value to the location
prop. Notice the injectHistory
method we have imported but not used anywhere. Now's the time to use it. Just add this line at the very end of your file
injectHistory(MyComponent);
MyComponent
is the name of the class declared above.
So the final code becomes:
import { Component, Prop, h, Watch } from "@stencil/core";
import { LocationSegments, injectHistory } from "@stencil/router";
@Component({
tag: "my-first-component",
})
export class MyComponent {
@Prop() name: string;
/**
* Remember, this should be `location only`
*/
@Prop() location: LocationSegments;
/**
* Now watch for any changes to the location property
*/
@Watch("location") onRouteChange(newRoute, oldRoute) {
// Do some epic shit
// Like changing document title or
// Route animations. Its your choice.
}
render() {
return <p>My name is {this.name}</p>;
}
}
injectHistory(MyComponent);
Here. Hope it helps. If you still run into issues, just ping me on Twitter. The link is in the footer.
Goodbye and Enjoy!