Skip to content Skip to sidebar Skip to footer

How Should I Use Redux With Nested Subcomponents That Won't Be Reused?

I'm working on a component that has many subcomponents, some of which are nested five deep. I'm interested in using redux for the advantage of having a single source of truth in a

Solution 1:

While the answer matt clemens posted does cover this at a high level, but I'll try to go into more depth here.

You can use connect() at any level. Doing so makes the component smart, since it knows where its props come from. A dumb component just has props, and they could come from anywhere. A smart component is coupled to redux; a dumb component is not.

There are differing opinions on this approach, but it is supported and valid.

Where to draw this line is entirely up to you, but let's look at an example. You have some chat client with a standard sidebar component, a message window, and the entry field for sending new messages.

+---------+--------------------------+||||Sidebar  |  Messages window||||||||||||||+--------------------------+||New Message Entry     **||||+---------+--------------------------+

The parent of all of these would use connect() to get the data from redux and feed it into these components via props. Now imagine that those two asterisks besides new message entry open up a settings panel (ignore the stupid placement, this is an example). Does it really make sense for new message entry to pass those props through? No, it doesn't.

To solve this you could create a special "container", lets call it SettingsContainer that used connect() to get its props and all it did was pass them down to SettingsPopup. SettingsPopup would not know about redux, and could still be tested/styled/reused normally, and the new message entry would only need to know about SettingsContainer, not any of its dependencies.

This approach scales well, but it has two penalties. First, the smart "wrapper" components like SettingsContainer have to be consumed by otherwise dumb components. This complicates the testing of the new message entry component. Second, the top-level component no longer exposes the entire graph of data dependencies, which makes things harder to reason about without delving deep into the component hierarchy.

These tradeoffs can be worth it, but you should be aware of them.

Solution 2:

You can use the newer React feature of context, via using 'react-redux''s component Provider. Using Provider will abstract away some of the implementation details of context, makes your markup quite expressive imho.

You basically setup a mini-global property, that all sub-components, dumb or smart can reference:

importReactfrom'react';
import {render} from'react-dom';
import {createStore} from'redux';
import {Provider} from'react-redux'; //Special Redux component to helpimport {reducers} from'./reducers.js';


varDeepDumbChild = (props, context) => (
    <div><pre>
            {JSON.stringify(data, null, 2)}
        </pre></div>
)


classSmartChildextendsReact.Component {
    render() {
        /* Use the global-like context */let data = this.context.store.getState();
        return (
            <div><DeepDumbChilddata={data}/></div>
        )
    }
}
SmartChild.contextTypes = {
    store: React.PropsTypes.object/* required */
}

/* No messy props :) */varApp = () => (<div><SmartChild/></div>);


render(
    <Providerstore={createStore(reducers)}><App/></Provider>,
    document.getElementById('app')
);

Solution 3:

UPDATE: If you want to try the approach below, have a look at https://github.com/artsy/react-redux-controller, which I recently published.

I think the best way to go is to map selectors to context at the root (container) component, rather than having a bunch of containers or using connect everywhere. I've done this in my own project and it's working beautifully. It adds a new pattern of annotating selectors with the PropTypes they produce. That let me use childContextTypes to allow all descendants to retain the same protections they have with propTypes. This is an advantage over Ashley Coolman's approach of passing down a big untyped object being passed down. I'm hoping to have time in the next couple days to factor it into its own library and publish.

In the meantime, I'd suggest making components smart, using connect liberally, rather than Tyrsius's approach of creating a whole bunch of containers, but that's just my opinion.

Post a Comment for "How Should I Use Redux With Nested Subcomponents That Won't Be Reused?"