Want to animate changes from one route to another? Reactium.Routing transition states give you control over the process.
Reactium uses the React Router under the hood by default, but we've made a few opinionated decisions to give you some powerful capabilities in the client application.
In Domain Model, we discuss the two methods for adding a routed component to your Reactium app. One is creating a route.js file which exports an object with properties supported by the React Router <Route> component. Likewise, your plugins can register routes dynamically of the same type using the Reactium SDKReactium.Routing.register().
These route objects have been extended in Reactium to give you control over a set of transitionary states between routes.
By default, registered routes are set to transitions: false This is intentional, because turning on transitions means you will need to write code to progress the routing state forward. This interrupts the quick / automatic loading of your routed component until such a time that your application is ready. e.g. you wish to animate the old component off the screen, and animate the new component onto the screen.
To turn on transitionary states for your routed component, set transitions to true when you define your route.
import Article from'./Article';import Product from'./Product';// This is the same as the defaultconsttransitionStates= [ { state:'EXITING', active:'previous', }, { state:'LOADING', active:'current', }, { state:'ENTERING', active:'current', }, { state:'READY', active:'current', },];// route.js can export an array of routes as wellexportdefault [ { path:'/article/:id', component: Article, transitions:true, transitionStates, type:'articles', }, { path:'/product/:id', component: Product, transitions:true, transitionStates, type:'products', },];
Article.js (version 1)
import React, { useEffect } from'react';import Reactium from'reactium-core/sdk';import { Link } from'react-router-dom';constArticle= (props) => {const {active,currentRoute,previousRoute,transitionState,transitionStates,changes, } = props;useEffect(() => {// Change Transition State on this component if not READY// every 1 secondconstto=setTimeout(() => {if (transitionState !=='READY') {Reactium.Routing.nextState(); } },1000);return () =>clearTimeout(to); }, [transitionState]);console.log('Article', { transitionState });if (transitionState ==='LOADING')return <div>Loading...</div>;return ( <div> <div>(Article) Route Status: {transitionState}</div> <Linkto={'/product/1'}>Product 1</Link> </div> );};exportdefault Article;
Product.js (version 1)
import React, { useEffect } from'react';import Reactium from'reactium-core/sdk';import { Link } from'react-router-dom';constProduct= (props) => {const {active,currentRoute,previousRoute,transitionState,transitionStates,changes, } = props;useEffect(() => {// Change Transition State on this component if not READY// every 1 secondconstto=setTimeout(() => {if (transitionState !=='READY') {Reactium.Routing.nextState(); } },1000);return () =>clearTimeout(to); }, [transitionState]);console.log('Product', {transitionState});if (transitionState ==='LOADING')return <div>Loading...</div>;return ( <div> <div>(Product) Route Status: {transitionState}</div> <Linkto={'/article/1'}>Article 1</Link> </div> );};exportdefault Product;
The default transition states are:
EXITING - exiting the previous routed component
LOADING - loading any data for the current routed component
ENTERING - the current component is entering
READY - the current component is fully loaded
The routed component will be passed a number of properties based on the current routing state:
Property
Description
active
"previous" or "current" indicating whether the currently rendered component is the previous exiting component, or if the current component is for the current route.
currentRoute
Object containing the routing configuration for the current matched route, including the location - router history.location object, match - the matched route object, params - route params, and search - URL search
previousRoute
If applicable, the object containing the routing configuration for the previous route, including the location - router history.location object, match - the matched route object, params - route params, and search - URL search
transitionState
The state of the routing transition, by default one of EXITING, LOADING, ENTERING, or READY, but customizable per route.
transitionStates
An array of the remaining states left to walk through, each with state and active properties.
changes
Object describing what caused the last routing state change (Boolean flags):
routeChanged - true when active route object changes
pathChanged - true when URL path has just changed
searchChanged - true when search params have just changed
notFound - true when no matching route was found for current route
transitionStateChanged - true when Reactium.Routing.nextState() was called from last routing state
Reactium.Routing will wait to progress to each transition state (including rendering your routed component), until your application callsReactium.Routing.nextState(). You can also subscribe to the routing state by registering a route listener, which will get calls whenever the routing state changes.
reactium-hooks.js
import op from'object-path';constroutingStateHandler=async updates => {if (['LOADING','READY'].includes(op.get(updates,'transitionState'))) {// unless LOADING or READY, waiting 1 second and then go to next stateawaitnewPromise(resolve =>setTimeout(resolve,1000));Reactium.Routing.nextState(); }};Reactium.Routing.routeListeners.register('my-routing-observer', { handler: routingStateHandler, order:Reactium.Enums.priority.low,});
Ok, now when clicking the links in one of our components, you'll see them EXITING, and then stop at LOADING. Let's add a hypothetical loading function to each component, and then progress the transition after loading is complete.
Article.js (version 2)
import React, { useState } from'react';import { Link } from'react-router-dom';import Reactium, { useAsyncEffect } from'reactium-core/sdk';import op from'object-path';constArticle= ({ active, currentRoute, previousRoute, transitionState, transitionStates, changes,}) => {const [ article,setArticle ] =useState();useAsyncEffect(async mounted => {// this component is current and we need to load the contentif (active ==='current'&& transitionState ==='LOADING') {// load the article contentconstarticle=awaitReactium.Cloud.run('content-retrieve', { type: { machineName:'article' }, objectId:currentRoute.params.id, });// set the component state and then progress the routing transitionif (mounted()) {setArticle(article);Reactium.Routing.nextState(); } } }, [active, transitionState]);if (transitionState ==='LOADING')return <div>Loading...</div>;return ( <divclassName={transitionState.toLowerCase()}> <div>(A) Route Status: {transitionState}</div> <div>Article: {op.get(article,'title','Unknown')}</div> <Linkto={'/product/1'}>Product 1</Link> </div> );};exportdefault Article;
Product.js (version 2)
import React, { useState } from'react';import { Link } from'react-router-dom';import Reactium, { useAsyncEffect } from'reactium-core/sdk';import op from'object-path';constProduct= ({ active, currentRoute, previousRoute, transitionState, transitionStates, changes,}) => {const [ product,setProduct ] =useState();useAsyncEffect(async mounted => {// this component is current and we need to load the contentif (active ==='current'&& transitionState ==='LOADING') {// load the product contentconstproduct=awaitReactium.Cloud.run('content-retrieve', { type: { machineName:'product' }, objectId:currentRoute.params.id, });// set the component state and then progress the routing transitionif (mounted()) {setProduct(product);Reactium.Routing.nextState(); } } }, [active, transitionState]);if (transitionState ==='LOADING')return <div>Loading...</div>;return ( <divclassName={transitionState.toLowerCase()}> <div>(Product) Route Status: {status}</div> <div>Product: {op.get(product,'sku','Unknown')}</div> <Linkto={'/article/1'}>Article 1</Link> </div> );};exportdefault Product;
Now our component is responding to the LOADING transition state for the route, causing a data load to happen, and progressing the routing state forward. You could even use a tool such as Tween Max to animate your page content onto the screen, and then progress the routing forward after tweening, or you could create css transitions from the transition state class on the element.