
SPFx Series: Extensies
Duiken in de essentiële bouwstenen van SPFx-extensies
Wanneer je begint met het bouwen van SharePoint Framework-componenten, is een van de eerste dingen waarbij je kunt struikelen het begrijpen van het verschil tussen props en state. Ik zie ontwikkelaars deze door elkaar halen, dus laten we dit eens en voor altijd duidelijk maken.
Het belangrijkste verschil tussen props en state is eenvoudig: props zijn configuratiewaarden die van buiten je component komen, terwijl state interne gegevens zijn die je component zelf beheert. Denk aan props als de instellingen die iemand je geeft, en state als de aantekeningen die je voor jezelf bijhoudt.
Props (kort voor properties) definiëren hoe je component zich moet gedragen of eruitzien. Het zijn de knoppen en schakelaars die gebruikers of ontwikkelaars kunnen aanpassen om je webonderdeel of extensie te personaliseren. Wanneer iemand je webonderdeel aan een pagina toevoegt en het eigenschappenvenster opent, wijzigen ze props.
Laten we een typisch voorbeeld bekijken:
export interface IHelloWorldWebPartProps {
title: string;
showTitle: boolean;
description: string;
maxItems: number;
}
In dit voorbeeld hebben we vier props gedefinieerd:
Deze props worden gedefinieerd in je webonderdeel-manifest en genereren automatisch velden in het eigenschappenvenster. Wanneer een gebruiker de titel wijzigt van “Hello World” naar “Welkom”, wijzigen ze een prop. Je component ontvangt deze nieuwe waarde en wordt dienovereenkomstig opnieuw gerenderd.
Hier is iets belangrijks: je component mag zijn eigen props nooit rechtstreeks wijzigen. Props stromen slechts in één richting — van ouder naar kind, van configuratie naar component. Als je een prop-waarde binnen je component probeert te wijzigen, doe je het verkeerd.
// DON'T DO THIS
public render(): void {
this.properties.title = "New Title"; // Wrong!
// Your render code...
}
Het eigenschappenvenster verwerkt prop-updates voor je. Wanneer iemand een waarde in het eigenschappenvenster wijzigt, roept SPFx automatisch de rendermethode van je component aan met de nieuwe prop-waarden.
Hier wordt het praktisch. Je definieert je props-interface, maar hoe maak je die velden eigenlijk aan in het eigenschappenvenster? Dit gebeurt in de methode getPropertyPaneConfiguration() van je webonderdeel. Zie ook de andere blogpost SPFx Series: Web part properties.
Laten we voortbouwen op ons eerdere voorbeeld, de IHelloWorldWebPartProps hierboven getoond. Nu moeten we de daadwerkelijke eigenschappenvenster-besturingselementen maken voor deze props:
import {
PropertyPaneTextField,
PropertyPaneToggle,
PropertyPaneSlider
} from '@microsoft/sp-property-pane';
export default class HelloWorldWebPart extends BaseClientSideWebPart {
protected getPropertyPaneConfiguration(): IPropertyPaneConfiguration {
return {
pages: [
{
header: {
description: "Configure your web part settings"
},
groups: [
{
groupName: "Display Settings",
groupFields: [
PropertyPaneTextField('title', {
label: 'Title',
description: 'The main heading for your web part'
}),
PropertyPaneToggle('showTitle', {
label: 'Show title',
onText: 'Visible',
offText: 'Hidden'
}),
PropertyPaneTextField('description', {
label: 'Description',
multiline: true,
rows: 3
}),
PropertyPaneSlider('maxItems', {
label: 'Maximum items to show',
min: 1,
max: 50,
step: 1,
showValue: true
})
]
}
]
}
]
};
}
}
Merk op hoe de eerste parameter van elk eigenschappenvenster-besturingselement overeenkomt met de eigenschapsnaam in je interface? Dat is de verbinding. Wanneer je PropertyPaneTextField('title', {…}) schrijft, vertel je SPFx: “dit tekstveld beheert de prop title”.
De magie gebeurt automatisch. Wanneer iemand “My News Feed” typt in dat tekstveld, werkt SPFx this.properties.title bij en roept je rendermethode aan. Je schrijft geen code om dit te verwerken — het werkt gewoon.
Je vraagt je misschien af waar standaardwaarden vandaan komen. Je stelt die in in je webonderdeel-manifest (HelloWorldWebPart.manifest.json):
{
"$schema": "https://developer.microsoft.com/json-schemas/spfx/client-side-web-part-manifest.schema.json",
"id": "abc123...",
"alias": "HelloWorldWebPart",
"componentType": "WebPart",
"preconfiguredEntries": [{
"groupId": "5c03119e-3074-46fd-976b-c60198311f70",
"group": { "default": "Other" },
"title": { "default": "Hello World" },
"description": { "default": "Shows a hello world message" },
"officeFabricIconFontName": "Page",
"properties": {
"title": "My News Feed",
"showTitle": true,
"description": "Latest news from our organization",
"maxItems": 10
}
}]
}
De waarden in het gedeelte properties zijn je standaardinstellingen. Wanneer iemand je webonderdeel voor het eerst aan een pagina toevoegt, zijn dit de waarden die ze zullen zien.
State is heel anders. State vertegenwoordigt gegevens die in de loop van de tijd veranderen en intern worden beheerd door je component. Het is de informatie die je component moet bijhouden terwijl het actief is.
Hier is een eenvoudige state-interface:
export interface IHelloWorldWebPartState {
selectedOption: string;
isLoading: boolean;
items: any[];
errorMessage: string;
}
Merk op hoe deze waarden verschillen van props:
Dit zijn geen configuratiewaarden die uit het eigenschappenvenster komen. Het zijn dynamische waarden die veranderen op basis van wat er op dit moment in je component gebeurt.
In React-gebaseerde SPFx-componenten (wat je de meeste tijd zult bouwen) beheer je state met behulp van React’s state management. Zo stel je het doorgaans in in je React-component:
export default class HelloWorld extends React.Component {
constructor(props: IHelloWorldProps) {
super(props);
// Initialiseer je state hier
this.state = {
selectedOption: '',
isLoading: false,
items: [],
errorMessage: ''
};
}
public componentDidMount(): void {
// Laad gegevens wanneer het component wordt gemount
this.loadItems();
}
private async loadItems(): Promise {
// Stel laadstatus in
this.setState({ isLoading: true, errorMessage: '' });
try {
const items = await this.fetchItems();
this.setState({ items: items, isLoading: false });
} catch (error) {
this.setState({
errorMessage: 'Failed to load items',
isLoading: false
});
}
}
private handleDropdownChange = (option: string): void => {
// Werk de state bij wanneer de gebruiker een selectie maakt
this.setState({ selectedOption: option });
}
public render(): React.ReactElement {
// Gebruik zowel props als state bij het renderen
const { title, showTitle } = this.props;
const { selectedOption, isLoading, items, errorMessage } = this.state;
return (
{showTitle && ## {title}}
{isLoading && }
{errorMessage && {errorMessage}}
{!isLoading && items.map(item => (
{item.title}
))}
);
}
}
Merk op dat de state wordt gebruikt in je component-bestand, niet in je webonderdeel-bestand!
Elke keer dat je this.setState() aanroept, rendert React je component automatisch opnieuw. Dit is krachtig, maar ook iets waar je voorzichtig mee moet zijn. Als je state te vaak of onnodig bijwerkt, kun je prestatieproblemen veroorzaken.