Roger Mitchell
Cofounder, Bluestone Labs
- What is React?
- Why (not) use React?
- React + Salesforce + You
- Advanced Patterns
- Demo!
- Questions & Answers
Speaker Note: BEFORE DIVING INTO MATERIAL:
- Ask by show of hands: who is familiar with a “Single Page App”?
- Ask by show of hands: who has written JavaScript before?
- Ask by show of hands: who is familiar with ReactJS?
- JavaScript library created + maintained by Facebook
- Built for creating UIs
- Embraces MV* to as View layer to your Model’s data
- Efficiently handles updates to browser’s DOM
- Mixes HTML and CSS into JS as “JSX”
- Components are composed to create an app
- Data are stored as “state” at highest level necessary
- Component state, functions are passed as “props”
- Use “props” to render, execute functions
- Only can modify state; rest of app inherits as props
- Uses “virtual DOM” to identify diffs with the DOM
Where's my Safe Harbor slide?
- Handles simple CRUD apps, data heavy pages
- Large community of web devs + designers
npm install
any packages to aid development- Augment your CRM dev team with your website’s dev team or agency
- Drop into a Visualforce page now, Lightning Component or App later
- Keep UI the same when switching out the backend
- React is not maintained by Salesforce, bugs happen
- Lack of “metadata awareness” when logic exists in JS
- Existing team has learning curve
- Hiring "framework of the day" devs is more difficult
- Large amount of local tooling is (really) required
- Requires using third party components available on npm (or building your own)
A journey into tooling, and treating the platform like an API.
- Sketch the UI on paper, or take a screenshot of a prototype
- Identify areas that can act as components
- Do not be afraid to nest components
- If you can abstract reasonably, do so
- Leverage others’ work to define components (e.g. SLDS)
- Apex Controller facilitates queries, DML via RemoteAction methods
- Visualforce Page acts as container in which to mount the React app
- Static Resource contains bundled components, helpers, third-party modules, etc
- Looks similar to importing JS for a jQuery project
<apex:page standardStylesheets="false" showHeader="false"
showChat="false" sidebar="false" docType="html-5.0"
controller="AccountManagementController"
applyBodyTag="false">
<body>
<link rel="stylesheet" type="text/css"
href="{!URLFOR($Resource.SLDS,
'assets/styles/salesforce-lightning-design-system-vf.min.css')}" />
<div id="app" class="react-vf"></div>
<script type="text/javascript"
src="{!URLFOR($Resource.AccountManagement, 'js/app.js')}"></script>
</body>
</apex:page>
- Use Node.js and npm to set up local project
- Install React to create components, establish state
- Install ReactDOM to mount the app into the browser’s DOM
- Use React Dev Tools for troubleshooting
- Optionally...
{
"name": "dynamic-page-mapping",
"version": "1.0.0",
"description": "",
"main": "webpack.config.js",
"author": "",
"license": "ISC",
"devDependencies": {
"babel-core": "^6.22.1",
"babel-loader": "^6.2.10",
"babel-preset-es2015": "^6.22.0",
"babel-preset-react": "^6.22.0",
"css-loader": "^0.26.1",
"style-loader": "^0.13.1",
"webpack": "^2.2.1",
"webpack-dev-server": "^2.4.5"
},
"dependencies": {
"react": "^15.4.2",
"react-dom": "^15.4.2"
}
}
{ "presets": [ "react", "es2015" ] }
let path = require('path');
module.exports = {
entry: './dev/js/App.js',
output: {
path: path.resolve(__dirname,
'./resource-bundles/AccountManagement.resource/js'),
filename: 'app.js'
},
module: {
loaders: [
{ test: /\.js$/, exclude: /node_modules/, loader: 'babel-loader' },
{ test: /\.css$/, loader: "style-loader!css-loader" }
]
}
};
Because JS has advanced (too) much in the last few years.
- Use single request to retrieve a “StateBundle”
- Deconstruct StateBundle into different objects/collections
- Call
setState()
to assign data to React’s state - Return StateBundle back after DML, repeat deconstruction
global class StateBundle
{
public List<Resource> resources;
public List<Card> cards;
public String recordTypeName;
}
export function getInitialState(recordId, context) {
Visualforce.remoting.Manager.invokeAction(
'T1ResourceVisualizationController.getInitialState',
recordId, true,
function(result, event) {
if(event.statusCode === 200) {
// decompose result
let Cards = result.cards;
let ResourceMap = buildResourceMap(result.resources);
let FilterMap = buildFilterCounts(Cards, context.state.SelectedView);
// get default filters
let Filters = defaultFilters;
// set state
context.setState({
RecordTypeName: result.recordTypeName,
Cards,
ResourceMap,
FilterMap,
Filters
});
} else {
console.error('Houston, we have a problem! 🌮');
}
}
);
}
- Serve app to localhost using webpack-dev-server
- Redirect browser requests to localhost using Requestly
- Prevent deploying static resource bundle
- Speed up your development cycles
Start webpack-dev-server
via Terminal...
webpack-dev-server --content-base
resource-bundles/YourResourceName.resource --https
Using Requestly, replace...
/https.*\/resource\/[0-9]+\/YourResourceName/ig
with...
https://localhost:8080
- Abstract app further with smaller components
- Use Field Sets and Custom Metadata Types to allow non-developers to control UI features
- Describe fields to support i18n and custom translations
- Leverage FieldSetReactor as utility to compose server-side details, serve with app’s StateBundle (i.e. app data)
@RemoteAction
public static List<FieldSetReactor.FieldDetails> getFields(
String fieldSetName,
String objectName)
{
return FieldSetReactor.getFieldDetails(fieldSetName, objectName);
}
Awww yeah...
Speaker Note:
- Changes to field set updates the UI
- Changes to labels updates the UI
- React Dev Tools for debugging + viewing metadata abstraction
- Requestly for efficient development
- React for Beginners by Wes Bos
- ES6 for Everyone by Wes Bos
- Building Admim Configurable UIs by Roger Mitchell
- Using Requestly in VF Dev Workflow by Roger Mitchell
- Christophe Conraet’s React collection
Roger Mitchell
Cofounder, Bluestone Labs