Developers are adopting Higher Order Components (HOC) Stateless Functional Components, and for good reason: they make it easier to achieve code reuse, a coveted aspiration of developers. There are many articles on HOC and Functional Stateless Components. Some are introductions and others describe deep technical aspects; I’ll explore refactoring existing components to create reusable elements. You might think that code reuse is overrated. Or it’s too hard, especially when looking to share code between the web and mobile. But here are a few benefits to consider: UX consistency, both within an application and across devicesMake cross-cutting upgrades: improve a component and update all its uses easilyreuse routing and authorization rulesSwitch libraries (for example, the apps below uses for state management, but could be swapped in) MobX Redux I’ll focus on using HOC and Functional Stateless Components to achieve reuse. You should already be familiar with the basics of and . has a good explaining their differences as well. React React Native Alexis Mangin post There is a lot of detail in the post; I explain the incremental process for refactoring the components. But if you are already familiar with these ideas (such as HOC), short on time, or just impatient, you can jump ahead to ( ) You can see the result and how easy it is to create additional applications with the reused components. The Payoff: Reusing the Component Final GitHub repo What are Higher Order Components and Stateless Functional Components? React 0.14 introduced Stateless Functional Components. They are functions that render components. The syntax is simpler; there are no class definitions nor constructors. And as the name implies, there is no state management (no uses of setState). I’ll comment more on this later and defer examples till later in this tutorial. has a good introduction . Cory House here Higher Order Components (HOC) are functions that create a new component. They wrap another component (or components), encapsulating the wrapped components. For example, let’s imagine you have a simple text box. You’d like to add autocomplete functionality. You could create a HOC and use the result as a new component. AutocompleteTextBox = makeAutocomplete(TextBox);<br> AutocompleteTextBox; const export //…later {AutoCompleteTextBox} from ‘./somefile’; import The Facebook documentation is . has a detailed as well. here franleplant post We’ll use both HOC and Stateless Functional Components in a few moments. Sample Application We’ll start with a very simple application: a simple search box. Enter a query and get a list of results. In this case, we’ll search for colors, by name. It will be a one screen application. It will not use routes nor multiple scenes as the focus is on component reuse. We will add a second pair of applications (React and React Native), which will reuse the components we extract. This has the baseline applications (The final result is .). I include the full details on building the React (web) and React Native (mobile) apps in the GitHub , but here is an outline: GitHub repo branch here README bootstraps the React applicationI use for the UI elements in the React/web app bootstraps the React Native applicationI use for state management. ( , creator of Mobx, has good tutorials and .) create-react-app Material UI react-native init MobX Michel Weststrate here here is a running demo of the web version. Screenshots of both are below (web, then mobile): https://colors-search-box.firebaseapp.com/ Refactoring To Reuse Refactoring to ReuseAchieving Code Reuse is About Perspective The basics of code reuse are simple. You extract methods (or classes or components) from one code base, replacing enclosed values with parameters. You then use the result in another code base. But the mileage of the reused element is often low and maintaining the shared code can become costly. I’ve achieved the sustained reuse by applying a few guidelines: , , and the . Separation of Concerns Single Responsibility Principle removal of duplication Separation of Concerns (SoC) and Single Responsibility Principle (SRP) are two sides of the same coin; the main idea is that a given code element should have one primary purpose. If there is one purpose, separation of concerns is a natural by-product; an element with one purpose probably won’t mix two areas of responsibility. Many IDE’s and developer tools can automate the consolidation of duplicate code. But removing duplication amongst similar designs is more difficult. You have to “see” the duplication, which might require rearranging code blocks. Applying these ideas is like moving puzzle pieces around, to find where they meet and what patterns they reveal. Let’s start by looking for duplication. Seeing Duplication The web and mobile applications have two main components. In the web application, App.js React, {Component} ; MuiThemeProvider ; {TextField, List, ListItem, Divider} {observer} ; injectTapEventPlugin ; injectTapEventPlugin(); observer( { propTypes = { : React.PropTypes.object.isRequired }; handleKeyDown = { ENTER_KEY = ; (event.keyCode === ENTER_KEY) { event.preventDefault(); .props.colors.search(); } }; handleQueryChange = { .props.colors.updateQuery(value); }; render() { listItems = .props.colors.results.map( { ( <ListItem key={`color-${index}`} primaryText={color.name} style={{backgroundColor: color.hex} }/> <Divider key={`divider-${index}`}/> </div> ); }); return ( <MuiThemeProvider> <div> <TextField hintText="Search..." floatingLabelFixed={true} fullWidth={true} value={this.props.colors.query} onChange={this.handleQueryChange} onKeyDown={this.handleKeyDown}/> <List> {listItems} </List> </div> </MuiThemeProvider> ); } }); import from 'react' import from 'material-ui/styles/MuiThemeProvider' import from 'material-ui' import from 'mobx-react' // (Make material-ui happy) // Needed for onTouchTap // http://stackoverflow.com/a/34015469/988941 import from 'react-tap-event-plugin' export default class App extends Component static colors ( ) => event const 13 if this ( ) => event, value this const this ( ) => color, index return < = ` ${ }`}> div key { color-div- index In the mobile application, SearchView.js React, {Component} ; { StyleSheet, View, TextInput, ListView, Text } ; {observer} ; styles = StyleSheet.create({ : { : , : , : }, : { : , : , : }, : { : , }, : { : , : , : , } }); dataSource = ListView.DataSource({ : r1.name !== r2.name}); observer( { propTypes = { : React.PropTypes.object.isRequired }; renderRow = { ( <Text style={styles.text}>{rowData.name}</Text> ); }; render() { ( <TextInput style={{height: 40, paddingLeft: 8, borderColor: 'gray', borderWidth: 1}} onChangeText={(text) => this.props.colors.updateQuery(text)} value={this.props.colors.query} returnKeyType={'search'} onSubmitEditing={() => this.props.colors.search()} /> <ListView enableEmptySections={true} dataSource={ dataSource.cloneWithRows(this.props.colors.results.slice())} renderRow={this.renderRow} renderSeparator={(sectionId, rowId) => <View key={rowId} style={styles.separator}/>} /> </View> ); } }); import from 'react' import from 'react-native' import from 'mobx-react/native' const container flex 1 backgroundColor '#eeeeee' marginTop 25 row flexDirection 'row' justifyContent 'center' padding 10 text flex 1 separator flex 1 height 1 backgroundColor '#8E8E8E' const new rowHasChanged ( ) => r1, r2 export default class SearchView extends Component static colors ( ) => rowData, sectionId, rowID return < = { }]}> View style {[styles.row, backgroundColor: rowData.hex </ > View return < = > View style {styles.container} The following outlines their structure. Almost the same, but the platform differences between React and React Native are in the way. The two components have similar structures. Ideally they would share components and look something like this: Our goal: a common, shared set of components And in pseudo-code, observer( { propTypes = { : React.PropTypes.object.isRequired }; renderSearchResult() { ( ) } render() { ( <SearchInput value={colors.query} onSubmit={colors.search} onTextChange={colors.updateQuery} /> <SearchResults/> </Container> export default class extends Component static colors //pseudo code return {color.name} < = }}> SearchResult style {{backgroundColor: color.hex </ > SearchResult return < > Container ) } } Unfortunately though, in the two applications, there is very little actual code in common. The components used in React (Material UI in this case) are different from those in React Native. But we can remove the conceptual duplication by first separating concerns and then refactoring the components to each have a single responsibility. Separation of Concerns and Single Responsibility Both and mix domain logic (our app logic) with the platform implementation and library integrations. We can improve the design if we isolate App.js SearchView.js UI implementation: e.g. separate and from the concept of search results ListItem ListView UX from state changes: e.g. separate submitting a search from updating and showing the results components: search input, search results (list) and an individual search result (list item) should each be a separate component Finally, refactoring should be done with automated tests, to ensure nothing breaks as you make changes. I’ll add some simple “smoke” tests, which can be found in this . GitHub repo/tag Extract Stateless Functional Components Let’s start with the easy and obvious when refactoring. React is about components, so let’s separate our components. We’ll use Stateless Functional Components, as they are easy to read. We can create as follows: SearchInput.js React ; {TextField} ; SearchInput = { handleKeyDown = { ENTER_KEY = ; (event.keyCode === ENTER_KEY) { event.preventDefault(); onSubmit(); } }; ( import from 'react' import from 'material-ui' const ( ) => {query, onSubmit, onQueryUpdate} const ( ) => event const 13 if return onQueryUpdate(value)} onKeyDown={handleKeyDown}/> ); }; SearchInput.propTypes = { query: React.PropTypes.string.isRequired, onSubmit: React.PropTypes.func.isRequired, onQueryUpdate: React.PropTypes.func.isRequired }; export default SearchInput; view rawSearchInput.js-1 hosted with ❤ by GitHub < = = = = = ) => TextField hintText "Search..." floatingLabelFixed {true} fullWidth {true} value {query} onChange {(event, value The essence of React is a UI /View framework and that is what we now have in this component. There are only two imported elements: React (requirement for JSX) and the from Material UI — no MobX, no , no Colors, etc. TextField MuiThemeProvider Event handling is delegated to the handlers (given as parameters), with the exception of watching for the key press. But this is an implementation concern of the input box and should be encapsulated in this component. (For example, a different UI widget library might include submit-on-enter-key behavior.) Enter Continuing our refactoring, we can create SearchResults.js. React ; {TextField} ; SearchInput = { handleKeyDown = { ENTER_KEY = ; (event.keyCode === ENTER_KEY) { event.preventDefault(); onSubmit(); } }; ( import from 'react' import from 'material-ui' const ( ) => {query, onSubmit, onQueryUpdate} const ( ) => event const 13 if return onQueryUpdate(value)} onKeyDown={handleKeyDown}/> ); }; SearchInput.propTypes = { query: React.PropTypes.string.isRequired, onSubmit: React.PropTypes.func.isRequired, onQueryUpdate: React.PropTypes.func.isRequired }; export default SearchInput; view rawSearchInput.js-1 hosted with ❤ by GitHub < = = = = = ) => TextField hintText "Search..." floatingLabelFixed {true} fullWidth {true} value {query} onChange {(event, value Similar to , this Stateless Functional Component is simple and only has two imports. Following Separation of Concerns (and SRP), the component for the individual search result is a parameter, ListItem. SearchInput.js We could have created a Higher Order Component to wrap ListItem . But since we are currently using Stateless Functional Components, we will defer using HOC. (Incidentally, we will refactor SearchResults.js to a HOC later.) For the individual search result, we’ll create ColorListItem.js React ; {ListItem, Divider} ColorListItem = { ( <ListItem primaryText={result.name} style={{backgroundColor: result.hex} }/> <Divider/> </div> import from 'react' import from 'material-ui' const ( ) => {result} return < > div ); }; ColorListItem.propTypes = { result: React.PropTypes.object.isRequired }; export default ColorListItem; view rawColorListItem.js-1 hosted with ❤ by GitHub And now, we need to refactor App.js. Extract Higher Order Components For readability, we’ll rename to For its refactoring, we have a few options. App.js SearchBox.js. Let pass to SearchResults (as a prop). SearchBox ColorListItem Have pass to , which would pass it to SearchResults index.js ColorListItem SearchBox Convert to to a Higher Order Component (HOC) SearchBox (1) would look like this: React, {Component} ‘react’; MuiThemeProvider ‘material-ui/styles/MuiThemeProvider’; {observer} ‘mobx-react’; injectTapEventPlugin ‘react-tap-event-plugin’; injectTapEventPlugin(); SearchInput ‘./SearchInput’; SearchResults ‘./SearchResults’; ColorListItem ‘./ColorListItem’; observer( { propTypes = { : React.PropTypes.object.isRequired }; render() { ( <div> <SearchInput query={this.props.colors.query} onQueryUpdate={value => this.props.colors.updateQuery(value)} onSubmit={() => this.props.colors.search()} /> <SearchResults ListItem={ColorListItem} results={this.props.colors.results.slice()}/> </div> </MuiThemeProvider> ); } }); import from import from import from // (Make material-ui happy) // Needed for onTouchTap // http://stackoverflow.com/a/34015469/988941 import from import from import from import from export default class SearchBox extends Component static colors return < > MuiThemeProvider There is nothing wrong with this. It would be a logical consequence of extracting and . But it binds to and, thus, violates Separation of Concerns. (It also limits the reuse of .) SearchInput.js SearchResults.js SearchBox ColorListItem SearchResults (2) fixes these concerns. React, {Component} ‘react’; MuiThemeProvider ‘material-ui/styles/MuiThemeProvider’; {observer} ‘mobx-react’; injectTapEventPlugin ‘react-tap-event-plugin’; injectTapEventPlugin(); SearchInput ‘./SearchInput’; SearchResults ‘./SearchResults import from import from import from // (Make material-ui happy) // Needed for onTouchTap // http://stackoverflow.com/a/34015469/988941 import from import from import from '; export default observer(class SearchBox extends Component { static propTypes = { searchStore: React.PropTypes.object.isRequired, ListItem: React.PropTypes.func.isRequired }; render() { return ( <MuiThemeProvider> <div> <SearchInput query={this.props.searchStore.query} onQueryUpdate={value => this.props.searchStore.updateQuery(value)} onSubmit={() => this.props.searchStore.search()} /> <SearchResults ListItem={ListItem} results={this.props.searchStore.results.slice()}/> </div> </MuiThemeProvider> ); } }); (I renamed the property to , to make the concept and reusability clearer.) colors searchStore But if we look at its usage, we have to pass as a prop. In , we would have, ColorListItem index.js React ‘react’; ReactDOM ‘react-dom’; SearchBox ‘./SearchBox’; ‘./index.css’; Colors ‘./colors’ ReactDOM.render( import from import from import from import import from , document.getElementById(‘root’) ); < = ()} = /> SearchBox searchStore {new Colors ListItem {ColorListItem} Compare it to the following: React ‘react’; ReactDOM ‘react-dom’; SearchBox ‘./SearchBox’; ‘./index.css’; Colors ‘./colors’ ColorListItem ‘./ColorListItem’; ColorSearchBox = SearchBox(ColorListItem); ReactDOM.render( import from import from import from import import from import from const , document.getElementById(‘root’) ); < = ()}/> ColorSearchBox searchStore {new Colors This is the if (3), a HOC is used. The distinction is subtle, but important. includes , encapsulating the specific search result component it uses. index.js ColorListItem ColorSearchBox (The searchStore, , is a prop. There should be one instance in the application, while there can be multiple instances of a given component, namely ColorSearchBox.) Colors So, we can make a HOC as follows. SearchBox.js React, {Component} ; MuiThemeProvider ; {observer} ; injectTapEventPlugin ; injectTapEventPlugin(); SearchInput ; SearchResults ; SearchBox = { observer( { propTypes = { : React.PropTypes.object.isRequired }; render() { ( <div> <SearchInput query={this.props.searchStore.query} onQueryUpdate={value => this.props.searchStore.updateQuery(value)} onSubmit={() => this.props.searchStore.search()} /> <SearchResults ListItem={ListItem} results={this.props.searchStore.results.slice()}/> </div> </MuiThemeProvider> ); } }); }; import from 'react' import from 'material-ui/styles/MuiThemeProvider' import from 'mobx-react' // (Make material-ui happy) // Needed for onTouchTap // http://stackoverflow.com/a/34015469/988941 import from 'react-tap-event-plugin' import from './SearchInput' import from './SearchResults' const ( ) => ListItem return class extends Component static searchStore return < > MuiThemeProvider Notice that looks more like the pseduo-code in the earlier section, . We’ll further refine it a bit later. SearchBox.js Seeing Duplication Refactoring React Native Components We can refactor the mobile application and extract components, following the previous pattern. I won’t go through all the details, such as extracting the SearchInput. But they are in the for the . README GitHub repo branch Instead, I’ll focus on the refactoring to a common , which our web (React) and mobile (React Native) applications will both use. SearchBox Extracting a Shared Component for Web and Mobile For clarity, I’ve renamed , and to , and , respectively. SearchInput.js SearchResults.js SearchBox.js WebSearchInput.js WebSearchResults.js WebSearchBox.js Let’s look at (Web) SearchBox.js React, {Component} ; MuiThemeProvider ; {observer} ; injectTapEventPlugin ; injectTapEventPlugin(); SearchInput ; SearchResults ; SearchBox = { observer( { propTypes = { : React.PropTypes.object.isRequired }; render() { ( <div> <SearchInput query={this.props.searchStore.query} onQueryUpdate={value => this.props.searchStore.updateQuery(value)} onSubmit={() => this.props.searchStore.search()} /> <SearchResults ListItem={ListItem} results={this.props.searchStore.results.slice()}/> </div> </MuiThemeProvider> ); } }); }; import from 'react' import from 'material-ui/styles/MuiThemeProvider' import from 'mobx-react' // (Make material-ui happy) // Needed for onTouchTap // http://stackoverflow.com/a/34015469/988941 import from 'react-tap-event-plugin' import from './SearchInput' import from './SearchResults' const ( ) => ListItem return class extends Component static searchStore return < > MuiThemeProvider Lines 2–10, 19, 20, 26, 27 are specific to React. , a container for Material UI components, is the only direct dependency on Material UI. But there are implicit dependencies via and . We can separate these dependencies by introducing a component. It will encapsulate the and render and as children. We can then create a new HOC. It will use , and . MuiThemeProvider SearchInput SearchResult SearchFrame MuiThemeProvider SearchInput SearchResults SearchBox SearchFrame SearchResults SearchInput Create a new SearchBox.js React, {Component} ; SearchBox = { { propTypes = { : React.PropTypes.object.isRequired }; render() { ( <SearchInput query={this.props.searchStore.query} onQueryUpdate={value => this.props.searchStore.updateQuery(value)} onSubmit={() => this.props.searchStore.search()} /> <SearchResults results={this.props.searchStore.results.slice()}/> </SearchFrame> ); } }; }; export default SearchBox import from 'react' const ( ) => SearchFrame, SearchInput, SearchResults return class extends Component static searchStore return < > SearchFrame This looks just like our pseduo-code from . Seeing Duplication Now, change the contents of to WebSearchBox.js React ; MuiThemeProvider ; injectTapEventPlugin ; injectTapEventPlugin(); WebSearchInput ; WebSearchResults ; SearchBox {observer} ; WebSearchFrame = { ( <div> {children} </div> ); }; WebSearchBox = observer(SearchBox(WebSearchFrame, WebSearchInput, WebSearchResults(ListItem))); WebSearchBox; import from 'react' import from 'material-ui/styles/MuiThemeProvider' // (Make material-ui happy) // Needed for onTouchTap // http://stackoverflow.com/a/34015469/988941 import from 'react-tap-event-plugin' import from './WebSearchInput' import from './WebSearchResults' import from './SearchBox' import from 'mobx-react' const ( ) => {children} return < > MuiThemeProvider </ > MuiThemeProvider const => ListItem export default (line 26) is the result of using the SearchBox HOC. WebSearchBox is a special React prop. In our case, it allows to include/render and , which are parameters provided by . More about the children prop can be found . children WebSearchFrame WebSearchInput WebSearchResults SearchBox here We will also to change to a HOC. It should encapsulate the as part of the HOC composition. WebSearchResults ListItem React, {Component} ; {List} WebSearchResults = { { propTypes = { : React.PropTypes.array.isRequired }; render() { listItems = .props.results.map( { ( <List> {listItems} </List> import from 'react' import from 'material-ui' const => ListItem return class extends Component static results const this ( ) => result, index return ); }); return ( < = ` ${ }`} = > ListItem key { result- index result {result}/ ); }; }; }; export default WebSearchResults; We now have our set of reusable components. (Here is the . Note, some directories were renamed for clarity.) GitHub repo/branch The Payoff: Reusing the Components We’ll create GitHub repository search apps. (GitHub allows for API use without an API key, which is convenient for this tutorial.) I’ll skip the bootstrapping details, but here is a summary create-react-app for the web app, react-native init for the mobile app add these modules: MobX, Material UI (web only), (for query string encoding)…details in package.json in the respective projects ( and ) qs web mobile The bulk of the effort is writing a new search store. Instead of colors, it searches GitHub repositories via the GitHub API. We can create github.js {extendObservable, runInAction} ; qs ; { () { extendObservable( , { : [], : }); } search() { self = ; ( { encodedQuery = qs.stringify({ : .query}); fetch( ) .then( { (response.ok) response.json(); reject( ); }) .then( { runInAction( { self.results = json.items; resolve(); }); }) .catch( { runInAction( { self.results = []; reject(error); }); }); }); } updateQuery(value) { runInAction( .query = value); } } import from 'mobx' import from 'qs' export default class GitHub constructor this results query '' const this return new Promise ( ) => resolve, reject const q this `https://api.github.com/search/repositories? ` ${encodedQuery} ( ) => response if return else ` : ` ${response.status} ${response.statusText} ( ) => json => () ( ) => error => () => () this (It’s unit test is .) here We’ll copy some common files, for simplicity. The GitHub repo uses to copy the files, as a slight convenience improvement. Sharing files/modules across Javascript projects is commonly done with NPM or Bower. (You can for registries.) You can also use , though they can be clunky. Since our focus is component reuse and not module publishing, we’ll do the hacky thing and copy files.) webpack pay private module Git submodules The rest is easy. Delete (and ) and replace the contents of with App.js App.test.js index.js React ; ReactDOM ; WebSearchBox ; ; {ListItem, Divider, Avatar} GitHub RepoListItem = { ( <ListItem primaryText={result.name} leftAvatar={<Avatar src={result.owner.avatar_url}/>}/> <Divider/> </div> ); }; RepoListItem.propTypes = { result: React.PropTypes.object.isRequired }; const RepoSearchBox = WebSearchBox(RepoListItem); ReactDOM.render( <RepoSearchBox searchStore={new GitHub()}/>, document.getElementById('root') ); import from 'react' import from 'react-dom' import from './WebSearchBox' import './index.css' import from 'material-ui' import from './github' const ( ) => {result} return < > div If you app, you should see npm start the github-web (You can also go to for a live version.) https://github-repo-search-box.firebaseapp.com React Native: GitHub mobile app Copy and the files, then create github.js MobileSearch*.js GitHubMobileSearchBox.js React ; { StyleSheet, View, TextInput, ListView, Text, Image } ; MobileSearchBox ; styles = StyleSheet.create({ : { : , : , : }, : { : , : , }, : { : , } }); RepoListItem = { ( <Image style={styles.thumb} source={{url:result.owner.avatar_url}} /> <Text style={styles.text}>{result.name}</Text> </View> import from 'react' import from 'react-native' import from './MobileSearchBox' const row flexDirection 'row' justifyContent 'center' padding 10 thumb width 48 height 48 text flex 1 const ( )=> {result} return < = > View style {[styles.row]} ) }; const GitHubSearchBox = MobileSearchBox(RepoListItem); export default GitHubSearchBox; and change contents to index.ios.js React, {Component} ; {AppRegistry} ; GitHub ; GitHubMobileSearchBox ; { render() { ( /** * Sample React Native App * https://github.com/facebook/react-native * @flow */ import from 'react' import from 'react-native' import from './github' import from './GitHubMobileSearchBox' export default class App extends Component return ); } } AppRegistry.registerComponent('GitHubMobile', () => App); < = ()}/> GitHubMobileSearchBox searchStore {new GitHub Two files, new mobile app. react-native run-ios We may have worked hard to refactor, but reusing the components to build two new apps was easy. Review and Wrap-Up Let’s look at a diagram of our components: (box icon is from , courtesy of ) thenounproject.com Tinashe Mugayi It’s nice to see the refactoring pay off. We could focus on the specific domain logic for the new applications. We only had to define the GitHub API client and how to render repository results. The rest comes for “free”. Furthermore, our components don’t have to deal with async issues. For example, they don’t know anything about the asynchronous fetch calls in github.js. This is one of the benefits of our refactoring approach and how we leveraged Stateless Functional Components. Promises and asynchronous programming only occur in the place it needs to, github.js, where the fetch call is made. wonderful It will be easier to extract components and reuse them, after you apply these techniques a few times. You may even write a reusable component at the start of a new view element, as the patterns become a norm in your coding. Also, I encourage to look into libraries like , which make it easier to write HOCs. recompose Take a look at the final and let me know how it goes with own refactoring of reusable components. GitHub repo