Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.
Headless Drupal + ReactJS
Oleksandr Linyvyi
Drupal Developer, Adyax
oleksandr.linyvyi@gmail.com
Why Drupal?
Drupal is used only for few
things
• Data storage (Drupal DB basically)
• Data provider (Services)
• Serve single HTML pag...
Frontend part is the
responsibility of React app
only
Why React?
React is used for
• Data fetching
• Data display
Basically it does all the UI stuff
React specific things
• Virtual DOM
• JSX
• Consequence - markup is mixed with JS
• And it is hard to get used to it 
• A...
<Button color=“green" borderSize={2}>
Click Me
</Button>
React.createElement(
Button,
{color: 'green', borderSize: 2},
'Cl...
Babel
http://babeljs.io/
Babel is a JavaScript compiler.
function Item(props) {
return <li>{props.message}</li>;
}
function TodoList() {
const todos = [
'finish doc',
'submit pr',...
Smart / dumb components
• Dumb (presentational) – are concerned
with how things look
• Smart (container) – are concerned w...
Redux
• Keeps application state in single place
• State is read only
• State transitions are predictable and
consistent
• ...
State
{
selectedNode: 1,
nodes: [
{
nid: 1,
title: 'Consider using Redux',
body: 'Lorem ipsum'
},
{
nid: 2,
title: 'Keep a...
Actions
{
type: 'SELECT_NODE',
nid: 2
}
Reducers
function selectedNode(state = null, action) {
switch (action.type) {
case 'SELECT_NODE':
return action.nid
defaul...
Dispatching an action
store.dispatch({
type: 'SELECT_NODE',
nid: 2
})
New state
{
selectedNode: 2, // changed
nodes: [
{
nid: 1,
title: 'Consider using Redux',
body: 'Lorem ipsum'
},
{
nid: 2,...
Package management
Where to search for packages?
• Npmjs.com
• Github.com
NPM is your tool:
$ npm install react react-dom ...
Some useful packages
• react, react-dom
• react-redux
• redux-thunk
• immutable
• reselect
• lodash
Demo app
• Load a list of nodes
• Display a list of clickable node titles
• Display node body on click on node title
Enable modules
Create a view
React part
Used packages
• React
• React-dom
• React-redux
• Redux-thunk
• Lodash
State
{
selectedNode: 1,
nodes: [
{
nid: 1,
title: 'Consider using Redux',
body: 'Lorem ipsum'
},
{
nid: 2,
title: 'Keep a...
Actions
{
type: 'STORE_NODES',
nodes: json
}
{
type: 'SELECT_NODE',
nid,
}
Reducers
function selectedNode(state = null, action) {
switch (action.type) {
case 'SELECT_NODE':
return action.nid;
defau...
Async action
export function loadNodes() {
return (dispatch) => {
return fetch('http://d8react.local/rest/nodes', {
creden...
import { connect } from 'react-redux';
import NodeList from 'NodeList';
const mapStateToProps = (state) => {
return { node...
Node list (dumb)
import React from 'react';
export default (props) => (
<ul>
{props.nodes.map((node) => {
return <li
key={...
Node content (smart)
import { connect } from 'react-redux';
import _ from 'lodash';
import NodeContent from 'NodeContent';...
Node content (dumb)
import React from 'react';
export default (props) => {
return
!!props.node ?
<div>{props.node.body[0]....
All together
import React from 'react';
import ReactDOM from 'react-dom';
import { createStore, applyMiddleware, compose }...
All together
const initialState = {
selectedNode: null,
nodes: [],
};
const store = createStore(
reducer,
initialState,
co...
Main magic
store.dispatch(loadNodes())
.then(() =>
ReactDOM.render(
<Provider store={store}>
<div>
<NodeListContainer />
<...
Index.html
• Contains <div id="app"></div>
• Load react application
• React takes care of the rest
Result
On click
On another click
Useful links
• https://medium.com/@nesbtesh/react-best-practices-
a76fd0fbef21
• https://medium.com/lexical-labs-engineeri...
Thank you!
Any questions?
Ask!
Headless drupal + react js   Oleksandr Linyvyi
Headless drupal + react js   Oleksandr Linyvyi
Upcoming SlideShare
Loading in …5
×

Headless drupal + react js Oleksandr Linyvyi

554 views

Published on

DrupalCampKyiv 2017

Published in: Internet
  • Be the first to comment

  • Be the first to like this

Headless drupal + react js Oleksandr Linyvyi

  1. 1. Headless Drupal + ReactJS Oleksandr Linyvyi Drupal Developer, Adyax oleksandr.linyvyi@gmail.com
  2. 2. Why Drupal?
  3. 3. Drupal is used only for few things • Data storage (Drupal DB basically) • Data provider (Services) • Serve single HTML page with React app
  4. 4. Frontend part is the responsibility of React app only
  5. 5. Why React?
  6. 6. React is used for • Data fetching • Data display Basically it does all the UI stuff
  7. 7. React specific things • Virtual DOM • JSX • Consequence - markup is mixed with JS • And it is hard to get used to it  • Also – a lot of 3rd party libs may (and should be) used
  8. 8. <Button color=“green" borderSize={2}> Click Me </Button> React.createElement( Button, {color: 'green', borderSize: 2}, 'Click Me‘ ) prevraschaets’a v
  9. 9. Babel http://babeljs.io/ Babel is a JavaScript compiler.
  10. 10. function Item(props) { return <li>{props.message}</li>; } function TodoList() { const todos = [ 'finish doc', 'submit pr', 'nag dan to review‘ ]; return ( <ul> {todos.map((message) => <Item key={message} message={message} /> )} </ul> ); }
  11. 11. Smart / dumb components • Dumb (presentational) – are concerned with how things look • Smart (container) – are concerned with how things work
  12. 12. Redux • Keeps application state in single place • State is read only • State transitions are predictable and consistent • Changes in state are made only by dispatching an action • And reducers describe how state is transformed by actions
  13. 13. State { selectedNode: 1, nodes: [ { nid: 1, title: 'Consider using Redux', body: 'Lorem ipsum' }, { nid: 2, title: 'Keep all state in a single tree', body: 'Dolor sit amet' } ] }
  14. 14. Actions { type: 'SELECT_NODE', nid: 2 }
  15. 15. Reducers function selectedNode(state = null, action) { switch (action.type) { case 'SELECT_NODE': return action.nid default: return state } }
  16. 16. Dispatching an action store.dispatch({ type: 'SELECT_NODE', nid: 2 })
  17. 17. New state { selectedNode: 2, // changed nodes: [ { nid: 1, title: 'Consider using Redux', body: 'Lorem ipsum' }, { nid: 2, title: 'Keep all state in a single tree', body: 'Dolor sit amet' } ] }
  18. 18. Package management Where to search for packages? • Npmjs.com • Github.com NPM is your tool: $ npm install react react-dom --save
  19. 19. Some useful packages • react, react-dom • react-redux • redux-thunk • immutable • reselect • lodash
  20. 20. Demo app • Load a list of nodes • Display a list of clickable node titles • Display node body on click on node title
  21. 21. Enable modules
  22. 22. Create a view
  23. 23. React part Used packages • React • React-dom • React-redux • Redux-thunk • Lodash
  24. 24. State { selectedNode: 1, nodes: [ { nid: 1, title: 'Consider using Redux', body: 'Lorem ipsum' }, { nid: 2, title: 'Keep all state in a single tree', body: 'Dolor sit amet' } ] }
  25. 25. Actions { type: 'STORE_NODES', nodes: json } { type: 'SELECT_NODE', nid, }
  26. 26. Reducers function selectedNode(state = null, action) { switch (action.type) { case 'SELECT_NODE': return action.nid; default: return state; } } function nodes(state = [], action) { switch (action.type) { case 'STORE_NODES': return action.nodes; default: return state; } }
  27. 27. Async action export function loadNodes() { return (dispatch) => { return fetch('http://d8react.local/rest/nodes', { credentials: 'include', }) .then((response) => { return response.json(); }) .then((json) => { dispatch({ type: 'STORE_NODES', nodes: json }); }) .catch((error) => console.log(error.message)) } }
  28. 28. import { connect } from 'react-redux'; import NodeList from 'NodeList'; const mapStateToProps = (state) => { return { nodes: state.nodes } }; const mapDispatchToProps = (dispatch) => { return { onClick: (nid) => dispatch({ type: 'SELECT_NODE', nid }) }; }; export default connect( mapStateToProps, mapDispatchToProps) (NodeList); Node list (smart)
  29. 29. Node list (dumb) import React from 'react'; export default (props) => ( <ul> {props.nodes.map((node) => { return <li key={node.nid[0].value} onClick={() => props.onClick(node.nid[0].value)} > {node.title[0].value} </li>; })} </ul> );
  30. 30. Node content (smart) import { connect } from 'react-redux'; import _ from 'lodash'; import NodeContent from 'NodeContent'; const mapStateToProps = (state) => { return { node: _.find(state.nodes, (node) => node.nid[0].value == state.selectedNode ) } }; export default connect(mapStateToProps)(NodeContent);
  31. 31. Node content (dumb) import React from 'react'; export default (props) => { return !!props.node ? <div>{props.node.body[0].value}</div> : null; };
  32. 32. All together import React from 'react'; import ReactDOM from 'react-dom'; import { createStore, applyMiddleware, compose } from 'redux'; import thunkMiddleware from 'redux-thunk'; import promiseMiddleware from 'redux-promise-middleware'; import { Provider } from 'react-redux'; import reducer from './reducers'; import { loadNodes } from './actions'; import NodeListContainer from './NodeListContainer'; import NodeContentContainer from './NodeContentContainer';
  33. 33. All together const initialState = { selectedNode: null, nodes: [], }; const store = createStore( reducer, initialState, compose(applyMiddleware( promiseMiddleware(), thunkMiddleware) ) );
  34. 34. Main magic store.dispatch(loadNodes()) .then(() => ReactDOM.render( <Provider store={store}> <div> <NodeListContainer /> <NodeContentContainer /> </div> </Provider>, document.getElementById('app') ) );
  35. 35. Index.html • Contains <div id="app"></div> • Load react application • React takes care of the rest
  36. 36. Result
  37. 37. On click
  38. 38. On another click
  39. 39. Useful links • https://medium.com/@nesbtesh/react-best-practices- a76fd0fbef21 • https://medium.com/lexical-labs-engineering/redux-best- practices-64d59775802e • https://egghead.io/courses/getting-started-with-redux • https://www.gitbook.com/book/rajdee/redux-in- russian/details • https://medium.com/@dan_abramov/smart-and-dumb- components-7ca2f9a7c7d0
  40. 40. Thank you! Any questions? Ask!

×