fix(icon): prevent ssr rendering

This commit is contained in:
Adam Bradley
2017-08-11 00:31:59 -05:00
parent 1c779aa501
commit b3ea4ecc75

View File

@ -19,7 +19,7 @@ export class Icon {
/** /**
* @input {string} Specifies the label to use for accessibility. Defaults to the icon name. * @input {string} Specifies the label to use for accessibility. Defaults to the icon name.
*/ */
@State() ariaLabel: string = ''; @Prop() ariaLabel: string = '';
/** /**
* @input {string} Specifies which icon to use. The appropriate icon will be used based on the mode. * @input {string} Specifies which icon to use. The appropriate icon will be used based on the mode.
@ -38,20 +38,13 @@ export class Icon {
@Prop() md: string = ''; @Prop() md: string = '';
@State() svgContent: string = null; @Prop({ context: 'isServer'}) private isServer: boolean;
getSvgUrl() { @State() private svgContent: string = null;
const iconName = this.iconName;
if (iconName !== null) {
return `${publicPath}svg/${iconName}.svg`;
}
return null;
}
get iconName() { private get iconName() {
// if no name was passed set iconName to null // if no name was passed set iconName to null
if (!this.name) { if (!this.name) {
return null; return null;
@ -117,21 +110,63 @@ export class Icon {
} }
static loadSvgContent(svgUrl: string, callback: {(loadedSvgContent: string): void}) { render() {
if (this.isServer) {
return <div class="icon-inner">{/* ssr */}</div>;
}
const svgUrl = getSvgUrl(this.iconName);
if (!svgUrl) {
// we don't have good data
return <div class="icon-inner">{/* invalid svg */}</div>;
}
const svgContent = svgContents[svgUrl];
if (svgContent === this.svgContent) {
// we've already loaded up this svg at one point
// and the svg content we've loaded and assigned checks out
// render this svg!!
return <div class="icon-inner" innerHTML={svgContent}></div>;
}
// haven't loaded this svg yet
// start the request
loadSvgContent(svgUrl, loadedSvgContent => {
// we're finished loading the svg content!
// set to this.svgContent so we do another render
this.svgContent = loadedSvgContent;
});
// actively requesting the svg, so let's just render a div for now
return <div class="icon-inner">{/* loading svg */}</div>;
}
}
function getSvgUrl(iconName: string) {
if (iconName !== null) {
return `${publicPath}svg/${iconName}.svg`;
}
return null;
}
function loadSvgContent(svgUrl: string, callback: {(loadedSvgContent: string): void}) {
// static since all IonIcons use this same function and pointing at global/shared data // static since all IonIcons use this same function and pointing at global/shared data
// passed in callback will have instance info // passed in callback will have instance info
// add to the list of callbacks to fiure when this url is finished loading // add to the list of callbacks to fiure when this url is finished loading
IonIcon.loadCallbacks[svgUrl] = IonIcon.loadCallbacks[svgUrl] || []; loadCallbacks[svgUrl] = loadCallbacks[svgUrl] || [];
IonIcon.loadCallbacks[svgUrl].push(callback); loadCallbacks[svgUrl].push(callback);
if (IonIcon.activeRequests[svgUrl]) { if (activeRequests[svgUrl]) {
// already requesting this url, don't bother again kicking off another // already requesting this url, don't bother again kicking off another
return; return;
} }
// add this url to our list of active requests // add this url to our list of active requests
IonIcon.activeRequests[svgUrl] = true; activeRequests[svgUrl] = true;
// kick off the request for the external svg file // kick off the request for the external svg file
const xhr = new XMLHttpRequest(); const xhr = new XMLHttpRequest();
@ -139,7 +174,7 @@ export class Icon {
// awesome, we've finished loading the svg file // awesome, we've finished loading the svg file
// remove this url from the active requests // remove this url from the active requests
delete IonIcon.activeRequests[svgUrl]; delete activeRequests[svgUrl];
// this response is the content of the svg file we're looking for // this response is the content of the svg file we're looking for
let svgContent = this.responseText; let svgContent = this.responseText;
@ -151,17 +186,17 @@ export class Icon {
} }
// cache the svg content in the global IonIcon constant // cache the svg content in the global IonIcon constant
IonIcon.svgContents[svgUrl] = svgContent; svgContents[svgUrl] = svgContent;
// find any callbacks waiting on this url // find any callbacks waiting on this url
const svgLoadCallbacks = IonIcon.loadCallbacks[svgUrl]; const svgLoadCallbacks = loadCallbacks[svgUrl];
if (svgLoadCallbacks) { if (svgLoadCallbacks) {
// loop through all the callbacks that are waiting on the svg content // loop through all the callbacks that are waiting on the svg content
for (var i = 0; i < svgLoadCallbacks.length; i++) { svgLoadCallbacks.forEach(cb => {
// fire off this callback which was provided by an instance // fire off this callback which was provided by an instance
svgLoadCallbacks[i](svgContent); cb(svgContent);
} });
delete IonIcon.loadCallbacks[svgUrl]; delete loadCallbacks[svgUrl];
} }
}); });
@ -176,45 +211,6 @@ export class Icon {
} }
render() { const activeRequests: {[url: string]: boolean} = {};
const svgUrl = this.getSvgUrl(); const loadCallbacks: {[url: string]: {(loadedSvgContent: string): void}[]} = [] as any;
if (!svgUrl) { const svgContents: {[url: string]: string} = {};
// we don't have good data
return <div class="icon-inner">{/* invalid svg */}</div>;
}
const svgContent = IonIcon.svgContents[svgUrl];
if (svgContent === this.svgContent) {
// we've already loaded up this svg at one point
// and the svg content we've loaded and assigned checks out
// render this svg!!
return <div class="icon-inner" innerHTML={svgContent}></div>;
}
// haven't loaded this svg yet
// start the request
Icon.loadSvgContent(svgUrl, loadedSvgContent => {
// we're finished loading the svg content!
// set to this.svgContent so we do another render
this.svgContent = loadedSvgContent;
});
// actively requesting the svg, so let's just render a div for now
return <div class="icon-inner">{/* loading svg */}</div>;
}
}
const IonIcon: GlobalIonIcon = {
activeRequests: {},
loadCallbacks: [] as any,
svgContents: {}
};
interface GlobalIonIcon {
activeRequests: {[url: string]: boolean};
loadCallbacks: {[url: string]: {(loadedSvgContent: string): void}[]};
svgContents: {[url: string]: string};
}