Skip to content

Instantly share code, notes, and snippets.

@adamterlson
Last active April 5, 2018 12:54
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save adamterlson/8607519051a4e102e247eed37261e17b to your computer and use it in GitHub Desktop.
Save adamterlson/8607519051a4e102e247eed37261e17b to your computer and use it in GitHub Desktop.
const propMap = (mapper) => (WrappedComponent) => (props) => <WrappedComponent {...mapper(props) } />
const mapStateToProps = (state) => {
user: state.currentUser
}
// This component will display the firstName of the current user
const MyComponent = compose(
connect(mapStateToProps),
propMap(props => ({
children: props.user.firstName
}))
)(Text)
// You must compose the component-returning-functions, not the returned components. I actually use a different
// term to avoid this confusion: let "enhancer" mean a function which takes a component as an argument and
// returns a new component. So, given:
const enhancer = (WrappedComponent) => {
const MyComponent = () => <WrappedComponent /> // Stateless functional component syntax
return MyComponent
}
// You must compose the *enhancers*, not the components, so:
const composition = compose(enhancer1, enhancer2)(ComponentToWrap)
// Also remember that `connect` has one more level of functional indirection. It's basically:
const connect = (mapStateToProps) => {
const enhancer = (WrappedComponent) => {
const MyComponent = () => <WrappedComponent />
return MyComponent
}
return enhancer
}
// So a composition of 'connect' and something else would look like:
const composition = compose(connect(mapStateToProps), enhancer2)(ComponentToWrap)
// In your specific case:
export default compose(ScreenHeaderWithImageConnect, CircularImageConnect)
// Is equivalent to:
export default compose(
connect(mapStateToProps2)(ScreenHeaderWithImage), // Wrong! This value is a component, not a function that returns a component (enhancer)
connect(mapStateToProps1)(CircularImage),
)
// This makes no sense. If you were to compose multiple connect functions together, they must be applied to *single presentational component*:
export default compose(
connect(mapStateToProps2), // Correct! The value of connect(mapStateToProps2) is a *function that returns a new component* (enhancer)
connect(mapStateToProps1),
)(ScreenHeaderWithImage)
// However, since you're trying to use compose with two totally different components, you seem to want presentation composition and not
// behavior composition. To compose presentation together, you simply use JSX:
const Header = compose(connect(mapStateToProps2), enhancer1)(ScreenHeaderWithImage)
const Image = compose(connect(mapStateToProps1), enhancer2)(CircularImage)
export default () => <Header><Image /></Header> // Or whatever makes sense for your UI
// Hope this helps!
@WhatUsersLove
Copy link

Thanks Adam.

I have updated the snack and also written another using the other compositional pattern:

https://snack.expo.io/@techytimo/redux-props-example
https://snack.expo.io/@techytimo/redux-component-composition

Thanks for sharing the tips!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment