Skip to content

Component Loading #1390

@bradwestfall

Description

@bradwestfall

I'm curious about best practices for my use-case (which I believe is probably very common). It's combination of react, redux, react-router but I believe the discussion is best suited for redux

Documentation and guides are very vague when it comes to component-to-component communication (of a non parent-child nature). Imagine using react-router where the overall page is derived of nested layout components such as

ReactDOM.render((
    <Router>
        <Route component={DefaultLayout}>
            <Route path="foo" component={FooLayout}>
                <Route path="products" component={Products}>
                <Route path="users" component={Users}>
                <Route path="widgets" component={Widgets}>
            </Route>
        </Route>
    </Router>
), document.getElementById('app'))

DefaultLayout looks like this:

export default React.createClass({
    render: function() {
        return (
            <div className="default-layout">
                <div class="receive-any-component"></div>
                <main>
                    {this.props.children}
                </main>
            </div>
        )
    }
})

For the sake of this example, FooLayout (loaded into this.props.children) can be any sub layout you want to imagine.

All three routes: /products, /users, or /widgets have a button in their component. When clicked, it will load a whole new component into the DefaultLayout's <div class="receive-any-component"></div> section. For example

Products component:

import store from 'path/to/store'

export default React.createClass({
    render: function() {
        return (
            <div className="product">
                Lorem ipsum...
                <button onClick={this.onClick}>Click Me</button>
            </div>
        )
    },
    onClick: function() {
        // There are several ways to have a component loaded DefaultLayout's
        // div.receive-any-component
    }
})

This whole example is over simplified. I'm using react-redux in the real thing. Official react docs only say one small bit on this type of use-case:

For communication between two components that don't have a parent-child relationship, you can set up your own global event system. Subscribe to events in componentDidMount(), unsubscribe in componentWillUnmount(), and call setState() when you receive an event. Flux pattern is one of the possible ways to arrange this.

So, I understand that I can use Redux to dispatch info whereby DefaultLayout is subscribed, but I need to load a whole component into DefaultLayout. It would seem to me there are two basic options, neither of which I feel are correct.

Option One

Have our Product component dispatch the component we want to load:

import store from 'path/to/store'
const componentToLoad = (
    <Whatever />
)

export default React.createClass({
    render: function() {
        return (
            <div className="product">
                Lorem ipsum...
                <button onClick={this.onClick}>Click Me</button>
            </div>
        )
    },
    onClick: function() {
        store.dispatch({
            type: 'LOAD',
            component: componentToLoad
        })
    }
})

Ultimately, I'd like the DefaultLayout to be unaware of what components it's loading, so this solution works out in that regards. But sending a component into redux just seems so wrong, but it works.

Option Two

Instead of dispatching a component, dispatch some state that indicates which component should be loaded. In this case, it would seem that DefaultLayout would have to import every possible component it might need to load (which in my real usecase is many), then subscribe to our state and use a switch statement to determine which one of our loaded components should be placed into .receive-any-component. This feels better from the redux end but feels crappy that DefaultLayout is aware of every possible component that it might need to load.

I'm not new to JS, but somewhat new to React/Redux. What am I missing?

And I apologize this question is so long. It's difficult for me to describe this any other way

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions