How to combine polymer reduct and <app-route>?
We are currently using <app-route>routing and are now implementing Redux with polymer-redux. However, it is unclear what is the best way to combine the two. Since it <app-route>maintains its own state, we cannot store it in our Redux store. However, for some actions that the user can perform, we also want to update the URL.
My current line of thinking is doing something with middleware, but it’s not entirely clear to me what is the best way to access / change routes <app-route>from within this middleware. How can we best approach this?
I ran into the same problem myself. The clash is that the basic principle of reduction is that it stands for a unique centralized state, while the polymer stands for several decentralized states. Matching both obviously requires some hacking from time to time. A good example is synchronizing browser URLs in redux state through a polymer (for use with a route application). Using app-location , I did the following:
<!-- my-app.html -->
<link rel="import" href="/bower_components/polymer/polymer.html">
<link rel="import" href="/bower_components/app-route/app-location.html">
<link rel="import" href="/src/redux/redux-behavior.html">
<link rel="import" href="/src/redux/route-action-creator.html">
<dom-module id="my-app">
<template>
<app-location route="{{_browserRoute}}"></app-location>
</template>
<script>
Polymer({
is: 'my-app',
behaviors: [ReduxBehavior, RouteActionCreator],
properties: {
_browserRoute: {
type: Object
}
},
observers: [
'_browserRouteChanged(_browserRoute.*)'
],
_browserRouteChanged: function(browserRoute) {
this.dispatch('browsed', browserRoute.base)
}
})
</script>
</dom-module>, my-app _browserRoute URL- . "" , _browserRoute.
<!-- route-action-creator.html -->
<script>
const ROUTE_ACTIONS = {}
const routeActions = {}
ROUTE_ACTIONS.BROWSED = 'ROUTE_BROWSED'
routeActions.browsed = function(route) {
return {
type: ROUTE_ACTIONS.BROWSED,
route: route
}
}
ROUTE_ACTIONS.REDIRECTED = 'ROUTE_REDIRECTED'
routeActions.redirected = function(path) {
window.history.pushState({}, null, path)
window.dispatchEvent(new CustomEvent('location-changed'))
return {
type: ROUTE_ACTIONS.REDIRECTED,
path: path
}
}
/**
* Route action creator behavior
* @polymerBehavior
*/
RouteActionCreator = {
actions: routeActions
}
</script><!-- route-reducer.html -->
<link rel="import" href="/src/redux/route-action-creator.html">
<script>
const reducers = {}
reducers.routeReducer = function(state, action) {
if (!state) {
return {
current: null
}
}
switch (action.type) {
case ROUTE_ACTIONS.BROWSED:
return Object.assign({}, state, {
current: action.route
})
case ROUTE_ACTIONS.REDIRECTED:
// Browser state is reduced in action creator because it uses an event
return state
default:
return state
}
}
</script>,
statePath: 'route.current'
.
this.dispatch('redirected', '/some-path')
, .
, app-route, polymer-redux app-route redux.
( ):
<link rel="import" href="../bower_components/polymer/polymer.html">
<link rel="import" href="../bower_components/app-route/app-location.html">
<link rel="import" href="../bower_components/app-route/app-route.html">
<dom-module id="my-router">
<style>
</style>
<template>
<app-location route="{{route}}" id="location" use-hash-as-path></app-location>
<app-route
active="{{active}}"
route="{{route}}"
pattern="/:step/:id"
data="{{page}}"
tail="{{tail}}">
</app-route>
</template>
<script>
(function() {
'use strict';
Polymer({
is: 'my-router',
behaviors: [ ReduxBehavior ],
properties: {
page: {
type:Object,
value: function(){ return {};},
},
currentAnalysisId: {
type:String,
statePath: 'id',
},
currentStep: {
type:String,
statePath:'currentStep',
},
active:{
type: Boolean,
observer:'_onInValidRoute'
}
},
observers: [
'_changeRoute(page)',
'_changeStepOrAnalysisId(currentStep,currentAnalysisId)',
],
actions: {
changeStep: function(step) {
return {
type: 'CHANGE_CURRENT_STEP',
step,
}
},
loadAnalysis: function(id,step) {
return {
type: 'LOAD_ANALYSIS',
id,
step,
}
},
},
_initialized : false,
ready: function() {
// required otherwise if navigating to a sub-route for the first time will be reset, by the localstorage initial redux state update
this._initialized = true;
},
_changeRoute: function(page) {
// required because otherwise
this.debounce('route_update',()=>{
let step = page.step;
let id = page.id;
if (id && this.getState().id !== id) {
ga('send', 'event', 'Analysis', 'load');
this.dispatch('loadAnalysis',id,step)
}
else if (this.getState().currentStep !== step) {
this.dispatch('changeStep',step);
}
ga('send', 'pageview');
},1);
},
_changeStepOrAnalysisId: function(step, id) {
if (!this._initialized) {
return;
}
this.debounce('state_changed',()=>{
if (this.page.step !== step || (this.page.id !== id && this.page.id !== '' && id !== null)) {
this.page = {step,id};
}
})
},
_onInValidRoute: function(valid) {
if (!valid) {
this.async(()=> {
this.$.location.set('route.path','/start/');
})
}
},
});
})();
</script>
</dom-module>