Reader small image

You're reading from  React Components

Product typeBook
Published inApr 2016
Publisher
ISBN-139781785889288
Edition1st Edition
Tools
Right arrow
Author (1)
Christopher Pitt
Christopher Pitt
author image
Christopher Pitt

Christopher Pitt is a principal developer for SilverStripe in Wellington, New Zealand. He usually works on open source software, though sometimes you'll find him building compilers and robots.
Read more about Christopher Pitt

Right arrow

Chapter 9. Thinking of Plugins

In the previous chapter, we looked at a couple of design patterns that we could use to build our applications. There are reasons for and against the use of Flux and Redux, but they generally improve the structure of React applications.

A good structure is essential for any large-scale application. Cobbling things together may work for small experiments, but design patterns are an integral part of maintaining anything larger. They do not say much in the way of creating extendable components, though. In this chapter, we're going to look at a few ways that we can use to make our components extendable by replacing them, injecting functionality, and composing interfaces from dynamic lists of components.

We're going to review a few related software design concepts and take a look at how they can assist us (and others) when we want to replace parts of our application with modified components and alternative implementations.

Dependency injection and service location


Dependency injection and service location are interesting concepts that are not limited to React development. To really understand them, let's move away from components for a while. For a moment, imagine that we wanted to create a sitemap. To do this, we could perhaps use code resembling the following code:

let backend = {
    getAll() {
        // ...return pages
    }
};
class SitemapFormatter {
    format(items) {
        // ...generate xml from items
    }
}
function createSitemap() {
    const pages = backend.getAll();
    const formatter = new SitemapFormatter();
  
    return formatter.format(
        pages.filter(page => page.isPublic)
    );
}

let sitemap = createSitemap();

In this example, createSitemap has two dependencies. Firstly, we fetch pages from backend. This is a kind of global storage object. We used something similar to this when we looked at the Flux architecture.

The second dependency is to the SitemapFormatter implementation...

Extending with callbacks


Another method to create more pluggable components is to expose (and act on) event callbacks. We saw something similar already, but let's take a look at this anyway. Suppose we have a PageEditorComponent class, as follows:

import React from "react";

class PageEditorComponent extends React.Component {
    onSave(e, refs) {
        this.props.onSave(e, refs);
    }
    onCancel(e, refs) {
        this.props.onCancel(e, refs);
    }
    render() {
        let refs = {};

        return (
            <div>
                <input type="text"
                    ref={ref => refs.title = ref} />
                <input type="text"
                    ref={ref => refs.body = ref} />
                <button onClick={e => this.onSave(e, refs)}>
                    save
                </button>
                <button onClick={e => this.onCancel(e, refs)}>
                    cancel
                </button>
           ...

Stores, reducers, and components


Building on these concepts, the final thing that we want you to look at is how this all fits together inside a Redux architecture.

Note

If you've skipped ahead to this chapter, make sure that you have a firm understanding of Redux by reading the previous chapter.

Let's begin with a PageComponent class (for individual pages, in a list):

import React from "react";

class PageComponent extends React.Component {
    constructor(props) {
        super(props);
        this.state = props.store.getState();
    }
    componentDidMount() {
        this.remove = this.props.store.register(
            this.onChange
        );
    }
    componentWillUnmount() {
        this.remove();
    }
    onChange() {
        this.setState(this.props.store.getState());
    }
    render() {
        const DummyPageViewComponent = use(
            "App/DummyPageViewComponent"
        );

        const DummyPageEditorComponent = use(
            "App/DummyPageEditorComponent"
        );...

Summary


In this chapter, we looked at a few methods that we could use to make our components (and general architecture) open to extension without requiring core modification. There's a lot to take in here and not nearly enough community standardization for this to be the final word on pluggable components. Hopefully, there's enough here for you to design the right plugin architecture for your application.

In the next chapter, we will look at various ways to test the components and classes that we've built so far. We'll continue to see the benefits of things, such as dependency injection and service location, while also learning about a few new tools.

lock icon
The rest of the chapter is locked
You have been reading a chapter from
React Components
Published in: Apr 2016Publisher: ISBN-13: 9781785889288
Register for a free Packt account to unlock a world of extra content!
A free Packt account unlocks extra newsletters, articles, discounted offers, and much more. Start advancing your knowledge today.
undefined
Unlock this book and the full library FREE for 7 days
Get unlimited access to 7000+ expert-authored eBooks and videos courses covering every tech area you can think of
Renews at €14.99/month. Cancel anytime

Author (1)

author image
Christopher Pitt

Christopher Pitt is a principal developer for SilverStripe in Wellington, New Zealand. He usually works on open source software, though sometimes you'll find him building compilers and robots.
Read more about Christopher Pitt