Your First Web Part with ReactJS and the SharePoint Framework

SPFXandReact

In a previous article, I introduced the main concepts binding the SharePoint Framework (SPFX) and React JS. In this article, I’m going to begin to dive deeper into ReactJS by building a client web part that welcomes the current user. As with my previous article, I’m going to stay focused on learning the fundamentals of ReactJS while limiting the SPFX details to the essentials. You can get the source code for this article from my GitHub repository.

 

 

Getting Started

I started my new client web part project using the standard approach outlined in the previous article. This approach utilizes the SPFX generator to create the project files specifically for the ReactJS framework. I named my new client web part HelloUserPart. After the project was generated, I opened it in Visual Studio Code.

Although there are many files associated with the project, the place to start is with the file named HelloUserPart.tsx located in the /src/webparts/helloUserPart/components directory. This file is the main component of the project and is written in TypeScript. Normally, you would expect TypeScript files to have a ts extension, but this file has a tsx extension. This extension indicates that the TypeScript file supports the XML syntax known as JSX. JSX is a preprocessor step that adds XML functionality to JavaScript and allows you to write HTML directly into your ReactJS components. If you examine the file created by the SPFX generator, you can see JSX code. This JSX will be modified as I create my custom component.

Developing the Component

In order to modify the generated project to meet my needs, I first had to create interfaces to support the component properties and state. Properties and state are key concepts in ReactJS. Properties are used to carry configuration information from parent components to child components and should be thought of as read-only. State is the data used to render information within the component. State can change at any time (such as when an asynchronous REST call returns), which will cause ReactJS to redraw the user interface for your component. You should begin by defining interfaces for both properties and state.

export interface IHelloUserPartProps {
    busyMessage: string;
}
export interface IHelloUserPartState {
    data: string;
    isValid: boolean;
}

For my component, I defined a busyMessage property to specify the text to display during asynchronous operations. I also defined the state to include data for display and an isValid flag to indicate the validity of the current state. The idea is that my component will display the busy message while it executes an asynchronous REST call to retrieve the display name of the current user. When the data returns, the component state will change and the message will be redrawn to welcome the current user.

Once the interfaces were created, I returned to the main component. Here, I imported the interface definitions and used them in the component definition. Your custom ReactJS components must extend the base Component and specify the properties and state objects to be used during creation.

​import { IHelloUserPartProps } from './IHelloUserPartProps';
import { IHelloUserPartState } from './IHelloUserPartState';

export default class HelloUserPart
extends React.Component<IHelloUserPartProps, IHelloUserPartState> {}

Properties are typically passed into the component from its parent whereas state is set within the component. Therefore, properties are sent into the constructor while initial state is set in the constructor. When you initialize state, you must override the constructor and pass the properties to the parent.

constructor(props: IHelloUserPartProps) {
    super(props);
    this.state = { data: null, isValid: false };
}

After an instance is created, properties and state are subsequently available in components through the variables this.props and this.state. Remember that properties are considered read-only, so there is no need to set the value of this.props. State values are dynamic and expected to change; however, you should never update the state directly through this.state. Instead, ReactJS provides the function this.setState(). Invoking this function will cause ReactJS to redraw the component.

When working with client web parts in SPFX, you should expect to perform data access using SharePoint’s RESTful API. Calls to the RESTful API are made asynchronously, so you must be mindful of when calls are initiated and the state of the component when calls return. ReactJS provides a number of lifecycle functions that are called at key moments such as when a new node is inserted into the DOM or when a component renders.

  • componentWillUpdate – executed before component is rendered
  • componentDidUpdate – executed after component is rendered
  • componentWillMount – executed before node is added to the DOM
  • componentDidMount – executed after node is added to the DOM
  • componentWillUnmount – executed before node is removed from the DOM
  • shouldComponentUpdate(newProps, newState) – executed before component is updated

Along with lifecycle methods, you’ll also need a library for making asynchronous calls. Although you can select any library for use, SPFX makes the fetch() function available. The fetch() function is a simple Promise-based function for making asynchronous calls. If you have used any of the many similar libraries, you’ll find the syntax to be straightforward. For this project, I combined the componentDidMount() function with the fetch() function to make an asynchronous call to the SharePoint RESTful API and set the component state upon success.

public componentDidMount(): void {
    fetch(
        '../../_api/web/currentuser',
        {
            method: 'GET',
            credentials: 'same-origin',
            headers: {
                'accept': 'application/json'
            }
        }
        ).then(response => {
            return response.json();
        }).then(json => {
            console.log(json);
            this.setState({ data: json.Title, isValid: true });
        }).catch(e => {
            console.log(e);
        });
    }

The last step in developing the component is to initialize the properties when the web part is rendered. SPFX creates a parent web part for your component. In this case, the web part can be found in the HelloUserPartWebPart.ts file located in the /src/webparts/helloUserPart directory. Here, I simply modified the render() function to create an instance of my component and initialize the properties.

public render(): void {
    const element: React.ReactElement<IHelloUserPartProps > = React.createElement(
        HelloUserPart,
        {
            busyMessage: "Working on it..."
        }
    );
    ReactDom.render(element, this.domElement);
}

Trying It Out

Once the project is complete, it can be run directly from Visual Studio Code. Simply select View>>Integrated Terminal from the main menu. Inside the integrated terminal, type gulp serve. A browser will launch with the SharePoint Workbench. Unfortunately, the web part won’t work in this browser because the web page is a mock-up running outside of a SharePoint context. The solution is to leave the project running, navigate to the SharePoint Workbench in your online tenancy, and load the new client web part from there.

HelloUserWebPart

Final Thoughts

Although the component in this article is fairly simple, it demonstrates several key aspects of component development with ReactJS. First, I showed how to define properties and state for components. Second, I showed how the component lifecycle can be used to coordinate asynchronous calls to the SharePoint RESTful API. Third, I showed how to instantiate the component from the base web part. In future articles, I’ll take a look at more aspects of ReactJS such as forms and user interactions.