React View Switching with Custom Events
Tags: react, javascript, customevent
Published: 2018-08-19 04:34:01

---
title: React View Switching with Custom Events
published: true
description: Any React component that needs to switch the view can simply dispatch an event with a data payload. The payload contains any data the next view may need.
tags: react, javascript, customevent
---

_Originally published on [stevebrownlee.com](https://stevebrownlee.com/react-view-switching-custom-events/)._

In my discussions with people in the Nashville community, I discovered that most teams are using some form of routing package that listens to URL changes to trigger view rendering. Because of this, we show students how to do view switching with the [react-router-dom](https://www.npmjs.com/package/react-router-dom) package.

Some don't use URL routing. Not every Single Page Application needs it.

While I've been playing around with React, slowly building up techniques for proper instruction to our students at Nashville Software School, I've tried my hand at several different mechanisms for view switching. Last night, while I was using the `CustomEvent()` constructor in another JavaScript project, a &#x1F4A1; went off!

Instead of defining a function in the **Matriarch** component (that's what I call the component in every app that maintains application state) whose reference gets passed around, why not just listen for an event? Then any component that needs to switch the view based on user gesture, or other event, can simply dispatch an event with a data payload. The payload is optional, and contains any data the next view may need to do its job.

## ViewManager

I created a simple module in my app whose [responsibility](https://code.tutsplus.com/tutorials/solid-part-1-the-single-responsibility-principle--net-36074) is twofold - set up an event listener on a DOM element, and provide the ability to dispatch a custom event.

> src/modules/ViewManager.js

```js
const ViewManager = Object.create(null, {
    init: {
        value: function (selector, eventName, fn) {
            this.eventName = eventName
            this.element = document.querySelector(selector)
            this.element.addEventListener(this.eventName, fn)
        }
    },
    broadcast: {
        value: function (view, payload) {
            this.element.dispatchEvent(
                new CustomEvent(this.eventName, {
                    detail: {
                        view: view,
                        payload: payload
                    }
                })
            )
        }
    }
})

export default ViewManager
```


## Main Application

In React, the main component is defaulted to `App.js` when using `create-react-app`. Your main component may be something else.

In the constructor, the ViewManager is initialzed with three things:

1. The DOM element where the event listener will be attached.
2. The name of the custom event that will be broadcasted.
3. The local function reference to handle the event.

> src/App.js

```jsx
import React, { Component } from "react"
import ViewManager from "./modules/ViewManager"


class App extends Component {
    constructor(props) {
        super(props)

        // Initialize ViewManager for switching main view
        ViewManager.init("#root", "changeView", this.switch)
    }

    switch = event => {
        const _viewProps = Object.assign({
            notifications: notes,
            exampleAdditionalInfo: localStorage.getItem("preferences")
        }, event.detail.payload)

        // Update state to trigger the view change
        this.setState({
            currentView: event.detail.view,
            viewProps: _viewProps
        })
    }
    
    ...
    
    // Returns a component to be rendered in the JSX below
    ShowView = () => {
        switch (this.state.currentView) {
            case "profile":
                return <Profile {...this.state.viewProps} />
            case "results":
                return <SearchResults {...this.state.viewProps} />
            case "home":
            default:
                return <Home {...this.state.viewProps} />
        }
    }
    
    render() {
        return (
            <React.Fragment>
                <NavBar {...this.state.viewProps} />

                {this.ShowView()}
            </React.Fragment>
        )
    }
}
```

## Any Component

Any component can now import **`ViewManager`** and use the `broadcast()` method to trigger a view change. In this stripped down component, when the user clicks on a _View Profile_ hyperlink, a custom event is dispatched and the **`App`** component's listener triggers and switches the view.

> src/search/SearchResults.js

```jsx
import React, { Component } from "react"
import ViewManager from "../modules/ViewManager"

export default (props) => (
    <div className="searchResults">
        props.foundItems.users.map(user =>
            <a href="#" 
                className="btn btn-outline-success"
                onClick={() => {
                    // Switch to profile view with a data payload
                    ViewManager.broadcast("profile", {userId: user.id})
                }}
                >View profile</a>
        )
    </div>
)
```