I have spfx extension Application customizer which has very long loading time takes like 4.37 s, I was wondering how to improve the loading time.
Edit- I tried loading the react component in domElement but same result
.ts
import * as React from 'react';
import * as ReactDom from 'react-dom';
import { sp } from "@pnp/sp";
import { override } from '@microsoft/decorators';
import * as $ from 'jquery';
import { Log, SPEventArgs } from '@microsoft/sp-core-library';
import styles from "./NavigationDeApplicationCustomizer.module.scss";
import {
PlaceholderContent,
PlaceholderName,
BaseApplicationCustomizer
} from '@microsoft/sp-application-base';
import GlobalNav from "./Components/GlobalNav";
import { IGlobalNavProps } from "./Components/IGlobalNavProps";
import ReactFooter, { IReactFooterProps } from "./ReactFooter";
import { IGobalNavState } from "./Components/IGlobalNavState";
import { Dialog } from '@microsoft/sp-dialog';
import { SPHttpClient, SPHttpClientConfiguration, SPHttpClientResponse, ODataVersion, ISPHttpClientConfiguration } from '@microsoft/sp-http';
import * as strings from 'NavigationDeApplicationCustomizerStrings';
import * as ReactDOM from 'react-dom';
const LOG_SOURCE: string = 'NavigationDeApplicationCustomizer';
/**
* If your command set uses the ClientSideComponentProperties JSON input,
* it will be deserialized into the BaseExtension.properties object.
* You can define an interface to describe it.
*/
export interface INavigationDeApplicationCustomizerProperties {
// This is an example; replace with your own property
termGroupId: string;
termSetId: string;
Bottom: string;
}
/** A Custom Action which can be run during execution of a Client Side Application */
export default class NavigationDeApplicationCustomizer
extends BaseApplicationCustomizer<INavigationDeApplicationCustomizerProperties> {
private static headerPlaceholder: PlaceholderContent;
private _topPlaceholder: PlaceholderContent | undefined;
private _bottomPlaceholder: PlaceholderContent | undefined;
@override
public onInit(): Promise<void> {
Log.info(LOG_SOURCE, `Initialized ${strings.Title}`);
localStorage.clear();
super.onInit().then(_ => {
console.log("super oninit called");
sp.setup({
spfxContext: this.context,
defaultCachingTimeoutSeconds: 30,
globalCacheDisable: false
});
}).then((_) => {
console.log("Sp Initilize");
this.context.placeholderProvider.changedEvent.add(this, this._renderPlaceHolders);
this.context.application.navigatedEvent.add(this, () => {
Log.info(LOG_SOURCE, 'Navigated event');
this._renderPlaceHolders();
});
this._renderPlaceHolders();
});
return Promise.resolve();
}
private _renderPlaceHolders(): void {
console.log("NavigationDeApplicationCustomizer._renderPlaceHolders()");
console.log(
"Available placeholders: ",
this.context.placeholderProvider.placeholderNames
.map(name => PlaceholderName[name])
.join(", ")
);
// Handling the top placeholder
if (!this._topPlaceholder) {
this._topPlaceholder = this.context.placeholderProvider.tryCreateContent(
PlaceholderName.Top,
{ onDispose: this._onDispose }
);
// The extension should not assume that the expected placeholder is available.
if (!this._topPlaceholder) {
console.error("The expected placeholder (Top) was not found.");
return;
}
if (this.properties) {
// Add refrence of react component to this file.
/* const element: React.ReactElement<IGlobalNavProps> = React.createElement(
GlobalNav,
{
termGroupId: this.properties.termGroupId,
termSetId: this.properties.termSetId,
}
);
ReactDom.render(element, this._topPlaceholder.domElement);*/
if (this._topPlaceholder.domElement) {
this._topPlaceholder.domElement.innerHTML = ``;
const element: React.ReactElement<IGlobalNavProps> = React.createElement(
GlobalNav,
{
termGroupId: this.properties.termGroupId,
termSetId: this.properties.termSetId,
}
);
ReactDom.render(element, this._topPlaceholder.domElement);
}
}
}
// Handling the bottom placeholder
if (!this._bottomPlaceholder) {
this._bottomPlaceholder =
this.context.placeholderProvider.tryCreateContent(
PlaceholderName.Bottom,
{ onDispose: this._onDispose });
// The extension should not assume that the expected placeholder is available.
if (!this._bottomPlaceholder) {
console.error('The expected placeholder (Bottom) was not found.');
return;
}
const elem: React.ReactElement<IReactFooterProps> = React.createElement(ReactFooter);
ReactDOM.render(elem, this._bottomPlaceholder.domElement);
}
// if (this._bottomPlaceholder.domElement) {
// this._bottomPlaceholder.domElement.innerHTML = `
// <div class="${styles.app}">
// <span class="${styles.fTab}">Open Footer</span>
//<footer>
//</footer>
// </div>`;
// }
}
private _onDispose(): void {
console.log('[NavigationDeApplicationCustomizer._onDispose] Disposed custom top and bottom placeholders.');
}
}
.tsx
import * as React from 'react';
import { IGlobalNavProps } from "./IGlobalNavProps";
import { IGobalNavState } from "./IGlobalNavState";
import { Log } from '@microsoft/sp-core-library';
import { sp } from "@pnp/sp";
import "@pnp/sp/taxonomy";
import { dateAdd, PnPClientStorage } from "@pnp/common";
import { IOrderedTermInfo } from '@pnp/sp/taxonomy';
const myKey: string = "navigationElements";
import { IContextualMenuItem,
} from 'office-ui-fabric-react/lib/ContextualMenu';
import { ContextualMenuItemType, IButtonStyles, Icon, IconButton, IIconProps } from '@fluentui/react';
import { createTheme, ITheme } from 'office-ui-fabric-react/lib/Styling';
import { CommandBar, ICommandBarStyleProps } from "@fluentui/react/lib/CommandBar";
import styles from "../NavigationDeApplicationCustomizer.module.scss";
const theme: ITheme = createTheme({
semanticColors: {
bodyBackground: "#27348a",
bodyText: "#fff"
}
});
const CommandBarProps: ICommandBarStyleProps = {
theme: theme,
};
const buttonStyle: IButtonStyles = {
root: {
'&:hover': {
backgroundColor: "darken(someColor, 0.3) !important",
},
backgroundColor: "#27348a",
color: "#fff",
justifyContent:"center !important",
letterSpacing: "1px",
},
menuIcon: {
color: "#fff",
justifyContent: "center !important",
letterSpacing:"1px",
display:"flex"
}
};
export default class GlobalNav extends React.Component<IGlobalNavProps, IGobalNavState> {
private store = new PnPClientStorage();
constructor(props: IGlobalNavProps) {
super(props);
this.state = {
loading: false,
terms: []
};
}
public componentDidMount() {
this.setState({}, async () => {
// this portion is responsible for getting terms from term store
const cachedTermInfo = await this.store.local.getOrPut(myKey, () => {
return sp.termStore.groups.getById(this.props.termGroupId).sets.getById(this.props.termSetId).getAllChildrenAsOrderedTree({ retrieveProperties: true });
}, dateAdd(new Date(), "minute", 10));
if (cachedTermInfo.length > 0) {
console.log(cachedTermInfo);
this.setState({ terms: cachedTermInfo });
}
});
}
private menuItems(menuItem: any, itemType: ContextualMenuItemType) {
return ({
key: menuItem.id,
name: menuItem.defaultLabel,
itemType: itemType,
href: menuItem.children.length == 0 ?
((menuItem.localProperties != undefined && menuItem.localProperties[0].properties !== undefined && menuItem.localProperties[0].properties.length > 0) ?
menuItem.localProperties[0].properties.filter(x => x.key == "_Sys_Nav_SimpleLinkUrl")[0].value !== undefined ? menuItem.localProperties[0].properties.filter(x => x.key == "_Sys_Nav_SimpleLinkUrl")[0].value : null
: null)
: null,
subMenuProps: menuItem.children.length > 0 ?
{ items: menuItem.children.map((i) => { return (this.menuItems(i, ContextualMenuItemType.Normal)); }) }
: null,
isSubMenu: itemType != ContextualMenuItemType.Header,
buttonStyles: buttonStyle
});
}
public render(): React.ReactElement<IGlobalNavProps> {
var commandBarItems: any[] = [];
if (this.state.terms.length > 0) {
commandBarItems = this.state.terms.map((i) => {
return (this.menuItems(i, ContextualMenuItemType.Header));
});
}
return (
<>
{
this.state.terms.length > 0 &&
<div className={`ms-bgColor-neutralLighter ms-fontColor-white ${styles.app}`}>
<div className={`ms-bgColor-neutralLighter ms-fontColor-white ${styles.top}`}>
<img src="https://transparent.png" className={styles.headerlogo}/>
<CommandBar
className={styles.commandBar}
{...CommandBarProps}
items={commandBarItems}
/>
</div>
</div>
}
</>
);
}
}