I have just started my first SharePoint project and cannot figure out how to use my React components in my extension. Here are the relevant files.
Navbar.tsx:
import * as React from "react";
export const Navbar = props => <div>Hello world</div>;
ReactSharePointNavbarApplicationCustomizer.tsx:
import { override } from "@microsoft/decorators";
import { Log } from "@microsoft/sp-core-library";
import {
BaseApplicationCustomizer,
PlaceholderContent,
PlaceholderName
} from "@microsoft/sp-application-base";
import { Dialog } from "@microsoft/sp-dialog";
import * as strings from "ReactSharePointNavbarApplicationCustomizerStrings";
import styles from "./AppCustomizer.module.scss";
import { escape } from "@microsoft/sp-lodash-subset";
import * as Components from "./components";
import Navbar = Components.Navbar;
const LOG_SOURCE: string = "ReactSharePointNavbarApplicationCustomizer";
/**
* 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 IReactSharePointNavbarApplicationCustomizerProperties {}
/** A Custom Action which can be run during execution of a Client Side Application */
export default class ReactSharePointNavbarApplicationCustomizer extends BaseApplicationCustomizer<
IReactSharePointNavbarApplicationCustomizerProperties
> {
private _onDispose(): void {
console.log("No place holder.");
}
private _topPlaceholder: PlaceholderContent | undefined;
private _renderPlaceHolders(): void {
if (!this._topPlaceholder) {
this._topPlaceholder = this.context.placeholderProvider.tryCreateContent(
PlaceholderName.Top,
{ onDispose: this._onDispose }
);
if (!this._topPlaceholder) {
return;
}
if (this.properties) {
const Nav = Navbar(null);
if (this._topPlaceholder.domElement) {
this._topPlaceholder.domElement.innerHTML = `
<div class="${styles.app}">
<div class="ms-bgColor-themeDark ms-fontColor-white ${
styles.top
}">
${Nav}
${Navbar}
<div>Hello</div>
<Navbar/>
</div>
</div>`;
}
}
}
}
@override
public onInit(): Promise<void> {
Log.info(LOG_SOURCE, `Initialized ${strings.Title}`);
// Added to handle possible changes on the existence of placeholders.
this.context.placeholderProvider.changedEvent.add(
this,
this._renderPlaceHolders
);
// Call render method for generating the HTML elements.
this._renderPlaceHolders();
return Promise.resolve<void>();
}
}
components:
export * from "./Navbar";
My goal is to use my react component as a navigation bar, however I cannot manage to combine tsx and ts in this context.
I followed this guide: https://learn.microsoft.com/en-us/sharepoint/dev/spfx/extensions/get-started/using-page-placeholder-with-extensions
Outside of these files, the only modifications I made were to add a components folder, with the component and index you see above.
Please help me solve this challenge.
After working on this for a few hours, I have found the solution. I was coming at this the wrong way, I needed to use ReactDOM to insert my TSX components. Afterward it was normal React development. No need to try to insert elements in some fancy way as I was doing before.
Here is the working code.
ReactSharePointNavbarApplicationCustomizer.ts:
import * as React from "react";
import * as ReactDOM from "react-dom";
import { override } from "@microsoft/decorators";
import { Log } from "@microsoft/sp-core-library";
import {
BaseApplicationCustomizer,
PlaceholderContent,
PlaceholderName
} from "@microsoft/sp-application-base";
import { Dialog } from "@microsoft/sp-dialog";
import * as strings from "ReactSharePointNavbarApplicationCustomizerStrings";
import styles from "./AppCustomizer.module.scss";
import { escape } from "@microsoft/sp-lodash-subset";
import Navbar, { INavbarProps } from "./components/Navbar";
const LOG_SOURCE: string = "ReactSharePointNavbarApplicationCustomizer";
export interface IReactSharePointNavbarApplicationCustomizerProperties {}
export default class ReactSharePointNavbarApplicationCustomizer extends BaseApplicationCustomizer<
IReactSharePointNavbarApplicationCustomizerProperties
> {
private _onDispose(): void {}
private onRender(): void {
const header: PlaceholderContent = this.context.placeholderProvider.tryCreateContent(
PlaceholderName.Top,
{
onDispose: this._onDispose
}
);
if (!header) {
Log.error(LOG_SOURCE, new Error("Could not find placeholder PageHeader"));
return;
}
const elem: React.ReactElement<INavbarProps> = React.createElement(Navbar);
ReactDOM.render(elem, header.domElement);
}
@override
public onInit(): Promise<void> {
this.onRender();
return Promise.resolve<void>();
}
}
Navbar.tsx:
import * as React from "react";
import styles from "./Navbar.module.scss";
import NavbarItem from "../NavbarItem";
export interface INavbarProps {}
export default class Navbar extends React.Component<INavbarProps> {
constructor(props: INavbarProps) {
super(props);
}
public render(): JSX.Element {
return (
<div className={"ms-bgColor-themeDark ms-fontColor-white " + styles.nav}>
Hello world
</div>
);
}
}
As you can see, the components.ts export file was unnecessary. And I am sure other code may still be useless in these examples.
I found that importing tsx components into other tsx components works like normal React imports. Just import and insert as an element.