Parent-Child Components with ReactJS and SharePoint Framework

SPFXandReact
In a previous article, I introduced the CRUDSheet client web part, which is used to edit a contacts list in a spreadsheet user interface. I also explained the service for performing CRUD operations on the SharePoint list. In this article, I am going to cover the components that make up the project. The CRUDSheet project consists of several ReactJS components designed to represent elements in a spreadsheet. These components have a parent-child relationship representing the entire grid, a grid row, and a grid cell. Figure 1 shows the component hierarchy:

CRUDSheetArchitecture
                                                                      Figure 1 — Component Hierarchy

Understanding the CRUDSheet Component

The CRUDSheet component is the component that represents the spreadsheet itself. The CRUDSheet component receives a set of contacts through its properties when it is initialized. The CRUDSheet renders a CRUDRow component instance for each contact in the sheet.

 

 

When creating web parts with parent-child React components, you must always think about how the parent communicates with the child and how the child communicates with the parent. Parent-to-child communication is fairly straightforward and involves sending data to the child via its properties. The CRUDSheet communicates with the CRUDRow by sending an individual contact as shown in the following code:

{this.state.contacts.map(contact => {
    return <CrudRow key={contact.id} contact={contact}
        contactEdited={this.contactEdited}
        contactDeleted={this.contactDeleted} />;
})}

Children communicate with the parent component by utilizing callback functions sent in by the parent. Notice in the code, the CRUDSheet is passing functions to the child that can be called when a contact is edited or deleted.

Understanding the CRUDRow Component

The CRUDRow component is responsible for rendering a row within the spreadsheet. It renders a CRUDCell component for each property in a contact object as shown in the following code:
https://petri.com/anatomy-powershell-advanced-function <CrudCell key={this.contact.id + 10} readOnly={true} name=”Id”
value={this.contact.id.toString()} rowEdited={this.rowEdited} />

Notice that the CRUDRow passes callback functions to the CRUDCell in the same way that the CRUDSheet passed callback functions to the CRUDRow. The interesting thing about this cascading communication, it is possible to have components in the middle of the tree that do little more than relay callback function information. This may not be a big deal in a three-component sample but if you have many components in a tree, it can become quite cumbersome.

There are other strategies for communicating between components. For example, you could use an object outside of the component tree that all the components know about. This component could then hold information and functions that could be invoked by any client. You could also use a more formal approach and implement data flow management based on the Flux architecture. Flux is an architecture developed by Facebook to help solve communication problems in complex React solutions. For now, I will keep it simple but look for coverage of Flux in later articles.

Understanding the CRUDCell Component

The CRUDCell component is responsible for rendering a single cell within the sheet. Additionally, this component manages whether the individual cell is in edit mode or not. When the cell is double-clicked, the rendering changes from read-only span to an editable input tag. After editing is complete, the CRUDCell component invokes the appropriate callback function to communicate up the tree. When the CRUDSheet is notified that data in the sheet has changed, it executes a save to the SharePoint list and initiates a redrawing of the sheet.

Pulling it All Together

The SharePoint Framework is a unique environment for React development because the top of the component tree is always the client web part. Typically, component communication will begin and end there. In the sample code, you can see that the actual functions to call the service and interact with the SharePoint list reside in the web part.

public saveContact(contact:IContact): Promise<Contact[]>{
  return this.contactsService.saveContact(contact);
}
public deleteContact(contact:IContact): Promise<Contact[]>{
  return this.contactsService.deleteContact(contact);
}
public addContact(): Promise<Contact[]>{
  return this.contactsService.addContact();
}

Now that you have a better understanding of the sample, you should be in good shape to get the code from my GitHub repo and use this article series to get it going. In future articles, I will examine more advanced techniques and new SharePoint Framework capabilities.