Last active
April 5, 2018 12:54
-
-
Save adamterlson/8607519051a4e102e247eed37261e17b to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// 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! |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
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!