Usage
React Redux Subspace provides React bindings to create subspaces for components.
Creating a subspace for a component
SubspaceProvider
is a react-redux
compatible React component that subspaces it's children:
import React from `react`
import { SubspaceProvider } from 'react-redux-subspace'
import SubApplication from 'some-dependency'
class MyComponent extends React.Component {
render() {
return (
<SubspaceProvider mapState={(state) => state.subApp} namespace="subApp">
<SubApplication />
</SubspaceProvider>
)
}
}
By wrapping SubApplication
in a subspace, the state injected into mapStateToProps
of connected components within the subspace will be the state mapped from the mapState
prop. The namespace
prop will be used to namespace the actions dispatched from mapDispatchToProps
of connected components within the subspace.
For example, if the application's state looked like:
{
"subApp": {
"value": "example"
}
}
SubApplication
might look something like:
import React from "react"
import { setValue } from "./actions"
class SubApplication {
render() {
return (
<input
type="text"
value={this.props.value}
onChange={e => this.props.setValue(e.target.value)}
/>
)
}
}
const mapStateToProps = state => ({
value: state.value
})
const mapDispatchToProps = dispatch => ({
setValue: value => dispatch(setValue(value))
})
export default connect(
mapStateToProps,
mapDispatchToProps
)(SubApplication)
There is a restriction that a SubspaceProvider
must be mounted within a react-redux
Provider
, somewhere above it in the component tree:
import React from 'react'
import { createStore } from 'redux'
import { Provider } from 'react-redux'
import { SubspaceProvider } from 'react-redux-subspace'
import reducer from 'somewhere'
import SomeOtherComponent from 'some-other-dependency'
import SubApplication from 'some-dependency'
const store = createStore(reducer)
class App extends React.Component {
render: {
return (
<Provider store={store}>
<div>
<SomeOtherComponent />
<SubspaceProvider mapState={(state) => state.subApp} namespace="subApp">
<SubApplication />
</SubspaceProvider>
<div>
</Provider>
)
}
}
Higher-Order Component
react-redux-subspace
also provides a subspaced
HOC that wraps a provided component in a SubspaceProvider
which can be useful when you want to subspace a component, but don't want to do it in jsx, e.g. exporting the component or passing it as a prop:
import { subspaced } from "react-redux-subspace"
import SubApplication from "some-dependency"
export default subspaced(state => state.subApp, "subApp")(SubApplication)
import { BrowserRouter, Route } from "react-router-dom"
import { subspaced } from "react-redux-subspace"
import SubApplication from "some-dependency"
const App = () => (
<BrowserRouter>
<div>
<Route
path="/subApp"
component={subspaced(state => state.subApp, "subApp")(SubApplication)}
/>
</div>
</BrowserRouter>
)
Breaking out of a subspace
Sometimes it's necessary for a child component to be rendered outside the context of the current subspace. By wrapping a component in a ParentSpaceProvider
, it, and any of it's children will connect
and dispatch
within the context of the store that created the subspace:
import React from `react`
import { ParentSpaceProvider } from 'react-redux-subspace'
import ApplicationRequiringParentScope from 'some-dependency'
class MyComponent extends React.Component {
render() {
return (
<ParentSpaceProvider>
<ApplicationRequiringParentScope />
</ParentSpaceProvider>
)
}
}
ParentSpaceProviders
should only be required within the context of a SubspaceProvider
, however, if used within the root application scope, the children will connect
and dispatch
into the root store, assuming it is rendered within a react-redux
Provider
.
Render Props
React recommends using "render props" in certain situations to establish an inverted control between components. This can lead to trouble when the render props are passed to a subspaced component since any redux-connected components inside the render prop will find themselves inside a subspace that they do not wish to be in. Usually code inside a render prop is meant to execute in the environment exterior to the component with the prop.
import React from `react`
import { SubspaceProvider, ParentSpaceProvider } from 'react-redux-subspace'
import TableWithSelection from 'somewhere'
class MyComponent extends React.Component {
render() {
return (
<SubspaceProvider mapState={(state) => state.tableSelection} namespace="TABLE">
<TableWithSelection
renderRow={row =>
// Row's state here is just the table selection.
// <ParentSpaceProvider> gives us back the full
// state object which includes state.tableSelection
<ParentSpaceProvider>
<TableRow/>
</ParentSpaceProvider>
} />
</SubspaceProvider>
)
}
}
Higher-Order Component
react-redux-subspace
also provides a parentSpaced
HOC that wraps a provided component in a ParentSpaceProvider
which can be useful when you want to subspace a component, but don't want to do it in jsx, e.g. exporting the component or passing it as a prop:
import { parentSpaced } from "react-redux-subspace"
import ApplicationRequiringParentScope from "some-dependency"
export default parentSpaced()(ApplicationRequiringParentScope)