SHARING CODE BETWEEN REACT AND REaCT-NATIVE
GOOD, BAD & UNSHARABLE
bene@theodo.co.uk
Ben Ellerby
Types of Code
UI Render
Business Logic
Configuration
API / Formatting
DIFFERENT RENDER ENVIRONMENT
- Different render environments:
<div> != <View>
<ul> != <FlatList>
UI Render
ui rENDER coDE
UI Render
- React-Native-Web (no longer supported by Twitter and SSR issues)
- ReactXP (SSR issues and have not seen a project using it successfully)
- styled-components/universal (Same SSR issues as React-Native-Web and too experimental)
Styled-components
UI Render
Visual primitives for the component age.
const Button = styled.button`
border-radius: 3px;
padding: 0.25em 1em;
margin: 0 1em;
background: transparent;
color: palevioletred;
border: 2px solid palevioletred;
`;
Styled-components
/universal
UI Render
Styled-components
/universal
UI Render
Builds off React-Primitives
"Primitive React Interfaces Across Targets"
- Animated
- StyleSheet
- View
- Text
- Image
- Touchable
- Easing
- Dimensions
- PixelRatio
- Platform:(iOS, Android, Web, Sketch, VR,...)
TextInput
https://github.com/lelandrichardson/react-primitives
Styled-components
/universal
UI Render
Styled-components
/universal
UI Render
Sketch
React
React-Native
Styled-components
/universal
UI Render
Note that this is an experimental release: There might be bugs and there also isn’t a massive amount of documentation
Styled-components
/universal
UI Render
ui rENDER coDE
UI Render
I believe that Web, Mobile Web and Native Application environments all require a specific design and user experience.
It’s worth noting that we’re not chasing “write once, run anywhere.” Different platforms have different looks, feels, and capabilities, and as such, we should still be developing discrete apps for each platform, but the same set of engineers should be able to build applications for whatever platform they choose, without needing to learn a fundamentally different set of technologies for each. We call this approach “learn once, write anywhere.”
Types of Code
UI Render
Business Logic
Configuration
API / Formatting
Types of Code
API / Formatting
API calls, authentication and formatting of request & response data.
If we make a POST to a REST API on web, it's the same POST on native.
Types of Code
Config files, translation files and most constant data is not render environment specific.
If I update a translation on my app, it's likely I want that changed rolled out on my site too.
Configuration
Types of Code
Shared Config Object
Native Config Object
{
....,
msg: "foo",
}
Web Config Object
Configuration
Types of Code
Again environment independent.
If a user can only add 20 items to their basket, this rule will hold true in web and native equally.
Business Logic
Types of Code
UI Render
Business Logic
Configuration
API / Formatting
State Management & Data
+
State Management & Data
+
- modal open
- translations
- analytic event firing...
- product data
- search
- pagination...
State Management & Data
UI
Render Environment Independent
Our whole redux store is shared
Our Apollo queries are shared
Higher Order Components
HigerOrderComponent
WrappedComponent
props: { foo: "bar" }
props.foo //bar
Higher Order Components: Apollo
import React from 'react';
import { Query } from 'react-apollo';
const withData = (query) => WrappedComponent => {
return props => (
<Query query={query}>
{injectedProps =>
<WrappedComponent {...injectedProps} {...props} />};
</Query>
);
};
export default withData;
Higher Order Components: Apollo
All Apollo query HOCs are shared:
e.g. withSearchResults, withBasket, withProducts
Conditional Rendering
renderIfAuthorised
import React from 'react';
import { connect } from 'react-redux';
import { compose, branch, renderComponent } from 'recompose';
import { getUserPermissionSets } from 'login.selectors';
const mapStateToProps = state => ({
userPermissions: getUserPermissionSets(state),
});
export default (permission, UnauthorisedComponent) =>
compose(
connect(mapStateToProps),
branch(
({ userPermissions }) =>
!userPermissions.includes(permission),
renderComponent(UnauthorisedComponent),
),
);
APPROACH To Sharing
MadeNative
MadeWeb
MadeShared
APPROACH To Sharing
MadeShared
/hoc
/queries
/conditional-rendering
/config
/translations /colours
/types /api
/redux
/actions
/reducers
/selectors /sagas
APPROACH To Sharing
MadeShared
var path = require('path');
module.exports = {
entry: './shared/index.js',
output: {
path: path.resolve(__dirname),
filename: 'index.js',
libraryTarget: 'commonjs2',
},
module: {
rules: [
{
test: /\.js$/,
include: path.resolve(__dirname, 'shared'),
exclude: /(node_modules|bower_components|build)\//,
use: {
loader: 'babel-loader',
options: {
presets: ['env'],
},
},
},
],
},
externals: {
react: 'commonjs react',
'react-apollo': 'commonjs react-apollo',
},
};
Webpack config to transpile to commonjs2
APPROACH To Sharing
...
"dependencies": {
...
"made-shared":
"git+https://AUTHTOKEN:x-oauth-basic@github.com/REPO/made-shared.git#master-1.05",
...
...
- Using basic x-auth tokens of a 'bot' user with read-only access
- Using git tags as versions (#BRANCH-VERSION)
- `yarn link` for local dev
APPROACH To Sharing
...
"dependencies": {
...
"made-shared": "1.5.1",
...
...
Staying Generic...
Staying Generic...
Staying Generic...
4 Weeks with one change to the shared library!
App Center!
MadeNative
We use AppCenter as our App CI
It needs to pull the shared library, but it's private...
App Center!
MadeNative
Me: Hello, we’re wanting to have a shared library used in our project. This would require an npm install from a private NPM repo (through package cloud). What is the best practice for adding a private npm access on the AppCenter CI?
App Center!
MadeNative
Microsoft: We currently only support cloud git repositories hosted on VSTS, Bitbucket and GitHub. Support for private repos is not available yet but we are building new features all the time, you can keep an eye out on our roadmap for upcoming features.
App Center!
MadeNative
Conclusion
- Code sharing is a great advantage of React & React-Native
- Share your non-design render code.
- Your app and web app should have a different UX
- HOCs help share component logic
- Publishing a private npm package creates a good workflow
Conclusion
- Multi Repo approach can help the team build a mental model of code sharing
ben@ellerby.tech
https://www.linkedin.com/in/benjaminellerby/
React Amsterdam 2019: Sharing Code Between React and React-Native: What Not to Share
By Ben Ellerby
React Amsterdam 2019: Sharing Code Between React and React-Native: What Not to Share
Talk given at the React-Native-London meetup.
- 825