Created
September 21, 2017 16:37
-
-
Save petejodo/dedd0b765239e16f0fdb87ca2d3eb843 to your computer and use it in GitHub Desktop.
Merge Theme React HOC using Flow
This file contains hidden or 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
| // These are the things that have worked from my experimentation | |
| import React from 'react'; | |
| import MyWrappedComponent from './MyWrappedComponent'; | |
| // $ExpectError - missing `someProp` which is required, (good) | |
| <MyWrappedComponent />; | |
| <MyWrappedComponent someProp={1} />; // (good) | |
| <MyWrappedComponent someProp={1} theme={{}} />; // an empty object is fine since it's still a shape of Theme (good) | |
| <MyWrappedComponent someProp={1} theme={{ someClass: 'my-class' }} />; // (good) | |
| // $ExpectError - `anotherClass` isn't a property in the shape of Theme (good) | |
| <MyWrappedComponent someProp={1} theme={{ anotherClass: 'another-class' }} />; | |
| <MyWrappedComponent someProp={1} anotherProp="foo" />; // supposedly normal behavior (good) |
This file contains hidden or 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
| // @flow | |
| import * as React from 'react'; | |
| import classnames from 'classnames'; | |
| import type {HigherOrderComponent} from 'react-flow-types'; | |
| type Theme = { [className: string]: string }; | |
| export type MergeThemeHOC<T: Theme> = T => HigherOrderComponent<{theme?: $Shape<T>}, {theme: T}>; | |
| const mergeTheme: MergeThemeHOC<*> = (injectedTheme: Theme) => (Component: any): any => { | |
| return (props) => { | |
| let theme: Theme = injectedTheme; | |
| if (props && props.theme) { | |
| const passedTheme: $Shape<Theme> = props.theme; | |
| theme = Object.keys(passedTheme) | |
| .filter((key: string) => !!injectedTheme[key]) | |
| .reduce((accum: Theme, key: string) => { | |
| accum[key] = classnames(passedTheme[key], injectedTheme[key]); | |
| return accum; | |
| }, { ...passedTheme, ...injectedTheme }); | |
| } | |
| return <Component {...props} theme={theme} />; | |
| }; | |
| }; |
This file contains hidden or 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
| // @flow | |
| import React from 'react'; | |
| type MyComponentTheme = { | |
| someClass: string | |
| }; | |
| export type {MyComponentTheme as Theme}; | |
| type MyComponentProps = { | |
| someProp: number, | |
| theme: MyComponentTheme | |
| }; | |
| export default (props: MyComponentProps) => <div>{/* ... */}</div>; |
This file contains hidden or 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
| // @flow | |
| import Component from './MyComponent'; | |
| import type {Theme} from './MyComponent'; | |
| import mergeTheme from './mergeTheme'; | |
| import type {MergeThemeHOC} from './mergeTheme'; | |
| // BUILT CSS | |
| var style = { | |
| someClass: 'MyComponent__someClass___rD0by' // Commenting this line out will throw a flow error which is good | |
| }; // Adding an additional property with type string to this object won't throw an error though which is not preferable but also not a deal breaker | |
| const merge: MergeThemeHOC<Theme> = mergeTheme; | |
| const MyWrappedComponent = merge(style)(Component); | |
| MyWrappedComponent.displayName = 'MyWrappedComponent'; | |
| export default MyWrappedComponent; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment