Build Cleaner Client-side Code with React Functional Components and Hooks

March 11, 2020

When it comes to client-side rendering of a web-based user interface you have a number of options. In the new world of development using open source toolchains that could mean websites, SharePoint web parts using the SharePoint Framework (which may have a new name by the time you read this), Office Add-ins or Microsoft Teams tabs. New view rendering frameworks and SPA (Single Page Applications) crop up fairly frequently and wax and wane in popularity. But right now, the one I would recommend, assuming you have not already invested heavily in another one, is ReactJS.

React is very popular and is widely used by Microsoft, and is continually improving. Once you get used to the slightly strange syntax of the JSX and TSX files, and if you’re not too precious about separation of code and mark-up, you’ll quickly learn to love its component-based architecture.

The way most people build a React component in TypeScript is to extend the React.Component base class. If you have ever built a “Hello World” web part using the Yeoman SPFx generator and chose React as the framework, this is what you will get. If you built “old school” web parts in the past using .NET this will feel comfortingly familiar – we even get to override the Render method. TypeScript has made it easier to use classes because, even though classes have been introduced to the JavaScript language (or more strictly-speaking the ECMAScript 2015 standard) you can’t rely on this feature being available everywhere you want to run JavaScript. The TypeScript compiler takes care of this for you and also means you don’t have to deal with the complexity of code isolation patterns like modules. You just get what you would expect from a classical language, even though JavaScript is actually using prototypal inheritance behind the scenes.

But JavaScript is a functional language (in the broadest sense), and if you are interested in functional programming you might prefer to avoid classes when writing React components. Well you can, because you have always been able to create a React component with just a simple function:

function myComponent(myProps) {
    return Hello {}!;
It’s ridiculously simple. Even I can do file->new and write this from memory. No remembering the class syntax and the base class and what method I need to override, no faffing around with this and that or worrying about closures. It’s just a function that returns some React elements. In fact, this is a pure stateless function. It only depends on the properties you pass in. It has no side-effects and no state. Actually, a lot of useful React components are like that. So, you can use this straight away to write simpler code next time you need one of these stateless components.

A Stateless React Component

I have built a sample SPFx web part ( that uses a stateless function to reproduce the simple template web part created by the Yeoman generator. You can view the code on Github by following the link, where you will also find instructions for getting the sample working. It is actually a re-work of the React version of the Hello World web part that you get when you use the @microsoft/generator-sharepoint Yeoman generator with a few simplifications and, of course, a pure functional component. The web part is intended to be easier to understand for new developers building their first SPFx web part. If you run it, you will see a web part that is identical to the regular web part that results from running the generator.

SharePoint Framework Webpart

Although it looks identical to a Hello World web part created by any other means, it has been refactored as a pure functional component. This simplifies the code structure and will also gain you additional kudos when talking to computer scientists and functional code enthusiasts. The structure is a simple JavaScript function with the name of the component, a single argument containing the React props, and a simple return of the component rendering. Here’s the code for the React component in the sample:

import * as React from 'react';
import styles from './HelloWorld.module.scss';
import { IHelloWorldProps } from '../HelloWorldWebPart';
import { escape } from '@microsoft/sp-lodash-subset';
import * as Fabric from 'office-ui-fabric-react';

export default function HelloWorld(props: IHelloWorldProps) {
  return (
    <div className={styles.container}>
      <div className={styles.row}>
        <div className={styles.column}>
          <span className={styles.title}>Welcome to SharePoint!</span>
          <p>Customize SharePoint experiences using Web Parts.</p>
          <Fabric.PrimaryButton href="">
            Learn more</Fabric.PrimaryButton>

Additionally, the React elements returned have been simplified. In particular the “Learn more” button, which was constructed from HTML primitives in the Yeoman-generated sample, has been replaced by an Office-UI-Fabric PrimaryButton component. Office-UI-Fabric is a React component library that Microsoft have created to make it really easy to build a UI which is consistent with products like Microsoft Office and SharePoint.

What about Components with State?

All this is great if you have a simple component, but what about state, side effects or other complexities? To deal with this we need to use a fairly new React feature called React Hooks, which you can read about on the React website: React Hooks were introduced in version 16.8 of the React framework. If you are using a version of the SharePoint Framework older than 1.82 (which uses an older version of React by default) I recommend that you update to the latest version which will also use a reasonably up-to-date version of React.

Let’s look at another sample ( ) which performs conversions from decimal numbers to roman numerals. Because there is an input control where a user is typing a value, this React control needs to manage state. That’s why it can’t be a pure functional component like the previous example. By the way, if you implemented this the “old” way, using classes, you would need quite a bit of extra code to keep track of state. But using React Hooks it actually becomes very simple.

On line 11 of RomanNumerals.tsx the React.useState function is used to provide state:

const [value, setValue] = React.useState(parseInt(props.initialValue));

React.useState takes an initial value for the state variable and returns an array of two objects. The first is a variable containing the state value, and the second is a setter function for the value, and that’s pretty much it. We could refer to these as state[0] and state[1] or something, but the convention is to use the array destructuring operator to unpack them into local constants. The name of these is not important but by convention we use the form [foo, setFoo], etc. Whenever we need to use the current value of the state variable, we just refer to it (e.g. {value}), and wherever we need to change the value we call setValue(newValue). There is no need to use this because we are not inside a class, nor do we need to worry about the context of the this value, nor create a constructor to initialize state.

In the code we use the number input control to change the value of the state using a local function onChange, which simply sets a new value as the user types in characters:

<input type="number" min="0" max="9999999" value={value} onChange={onChange} />

The onChange function could be defined using a lambda expression, but in this case we have defined a local function:

function onChange(event) {

We also have a couple of additional buttons that can be used to increment and decrement the value which also demonstrates updating state with inline functions. Everything just works because the React framework will re-render the component whenever we update the state variable using the setValue function. If you need more complex state you could pass a more complex object to useState, but a better approach is often to simply call useState once for each variable that makes up the state.

The output rendering uses the value of the state variable and does a conversion using the romanToString function:

<h3>{props.resultCaption} {romanToString(value)}</h3>

Using React Hooks allows us to manage state in a very simple way, without the complexities around component lifecycle events like componentDidMount, constructors, or keeping track of different incarnations of the this variable.

Fetching Data from the Microsoft Graph

The previous example showed a React functional component that included state. In many cases, particularly when building extensions for SharePoint, Teams or Office, we also need to manage data fetched from a remote service. This can also be achieved using the recent React Hooks feature. The final example web part ( ) renders a list of the user’s Teams and, if enabled, a list of the Teams channels for each Team with a link to the channel.

This is an extension of the approach used in the React-Functional-Component and React-Functional-Stateful-Component samples.

The onInit method of BaseClientSideWebPart is overridden to initialise the PnPJS graph object. The web part is then able to get access to the Microsoft Graph using the PnPJS library. The User.Read.All permission is implicitly provided.

public onInit(): Promise<void> {
  return super.onInit().then(() => {
    graph.setup({ spfxContext: this.context });

As in the previous example we need to maintain the state of the component so this is provided by the React.useState hook:

const initialTeamsList: MSGraph.Group[] = null;
const [teamsList, setTeamsList] = React.useState(initialTeamsList);

React.useState takes an initial value for the state variable, which we initialise to null but by means of a strongly typed const. This means that we will get type checking and intellisense for the state object.

If we were writing a React component class, we would need to use various lifecycle methods like componentDidMount and componentDidUpdate, etc. With functional components and React Hooks we use a React method called useEffect, which is designed to allow you to include code that enables your functional component to manage side-effects (hence the name). The code to call the Microsoft Graph is very simple:

React.useEffect(() => { => { setTeamsList(teams); });
}, []);

We use the PnPJS library to get a list of Teams from the Microsoft Graph, and then use the setTeamsList method (which you may remember was the second element in the array returned by the React.useState function) to set the value of the state variable. Calling setTeamsList is very similar to calling setState() when doing things the ‘old way’. It will result in the component being re-rendered to reflect the changes to the state variable.

You might have noticed that there is a second argument to React.useEffect, and we have passed into it an empty array. This array contains any variables that we depend on, for example a filter or other display option – if they change it will result in the useEffect callback function being called again. If we omit the second argument altogether then the graph call will happen whenever the component is rendered, and since the promise causes a re-rendering, the result would be a nasty infinite loop. By providing an empty array we ensure that the useEffect callback only gets called when the component first loads.

For convenience we have rendered the dynamic bit of the web part into a variable called content. We can show a UI Fabric spinner if the data isn’t loaded, or a helpful message if the data returned is an empty array. Here is the TSX code that renders the list of Teams:

  { => (
    <li key={}>
      <Team channelID={} displayName={team.displayName} 
        showChannels={props.showChannels} />

Notice that we just take the teamsList (our state variable) and use a map function to render each team into a series of <li> elements. Each team is rendered using a <Team> component which we have defined in Team.tsx.

Using More React Components

The Team.tsx component is only responsible for rendering an individual team, and the structure of the component follows a similar pattern to that of TeamTracker.tsx. Notice first that we use a different approach to using the props by using the object destructuring operator to unpack the individual values from the outset, which can sometimes make the subsequent code a little clearer:

export default function Team({ channelID, displayName, showChannels }) {

Again, we use state to manage a list of channels and initialise it to an empty array. But in this case, we have a property showChannels that is the flag set by the user in the property pane. If this is enabled, we retrieve the channels from the Microsoft Graph using the PnPJS library, and if not, we set it to an empty array. We need to explicitly reset the array in case the user enables and then subsequently disables the showChannels option. Finally, notice that we now need to include a dependency for the second argument of useEffect so that the framework knows to call the method again if the value of showChannels changes.

const [channelsList, setChannelsList] = React.useState([]);
React.useEffect(() => {
  if (showChannels)
    graph.teams.getById(channelID).channels.get().then(channels => {
}, [showChannels]);

The rest of Team.tsx simply returns the rendering of the component with the name of the Team and a list of channels. If the channelsList is empty it will just render an empty <ul>.

If this were a real application, rather than a demonstration, you would need to decide whether it was efficient to make multiple graph calls, or whether to batch the calls in some way, which would probably make the code a little more complicated. If you end up with a large hierarchy of nested components you might also use the useContext hook to manage data that you retrieve at a higher level, to be referenced in lower level components without having to pass everything down through props.

Wrapping Up

All of the samples described above are in the SharePoint/sp-dev-fx-webparts repository on Github under the samples directory with names starting “react-functional-“. To download them you can git clone this repository. In the directory for the sample you need to do an npm install and then a gulp serve to run the web part in the local workbench. These sample probably don’t use the latest version of the SharePoint Framework, so you might prefer to clone the projects and then paste the pertinent bits of code into your own freshly generated starter project using the latest version of the Yeoman generator.

The local workbench will work for the first two samples, but the final sample will need to run in an actual Office 365 tenant, otherwise the PnPJS promise will never return and so you will just see the loading spinner. In the react-functional-component-with-data-fetch directory, run npm install to resolve all the dependencies. Once this has completed you can run gulp serve –nobrowser to test the web part in the workbench of your tenant (

I hope you like using the functional component approach and React Hooks. I think it results in cleaner code which is much easier to write and understand. I can’t wait to present on this fascinating topic at the European Collaboration Summit in Weisbaden in June 2020, and I hope to see you there!

Collaboration means two-way communication!

Did you like this article? Are you interested in this topic? Would you like to share your knowledge and experience with the authors and other readers? Our #communityrocks group on Facebook is bringing everyone involved together: authors, editors and readers. Join us in sharing knowledge, asking questions and making suggestions. We would like to hear from you! 

Join us on Facebook

Related Articles

Submit a Comment

Your email address will not be published. Required fields are marked *