Using React to create reusable components for Confluence extension points saves time and allows for a richer user experience. Join Matt Jensen, an Atlassian developer for over 10 years, for a session on using React to modularise the UI layer of your Confluence add-on, then bringing it together to take advantage of the common components. Matt will demonstrate the benefits of React for UI elements like macros, pages, and dialogs.
Matthew Jensen, Development Team Lead, Atlassian
7. Client Side
We use extended JavaScript
on the client side to create
the UI Components.
Server Side
In this example we use server
side JavaScript by using
NodeJs.
JavaScript Everywhere
27. Components
function Clock(props) {
return <span>{moment().format()}</span>;
}
ReactDOM.render(
<Clock />,
document.getElementById('root')
);
Functional
Classes
State
28. Components
function Clock(props) {
return <span>{moment().format()}</span>;
}
ReactDOM.render(
<Clock />,
document.getElementById('root')
);
Functional
Classes
State
29. Components
function Clock(props) {
return <span>{moment().format()}</span>;
}
ReactDOM.render(
<Clock />,
document.getElementById('root')
);
Use a function to define a Component
Functional
Classes
State
34. class Clock extends React.Component {
render() {
return <span>{moment().format()}</span>;
}
}
ReactDOM.render(
<Clock />,
document.getElementById('root')
);
Components
Functional
Classes
State
Use a class to define a Component
35. Components as Classes
Classes
Classes can benefit from
inheritance, composition and
other object orientation
strategies.
Stateful
Components defined as classes
can define their own state and
lifecycle.
39. Components
Functional
Classes
class Clock extends React.Component {
constructor(props) {
super(props);
this.state = { date: moment() };
}
render() {
return (
<span>
{this.state.date.format()}
</span>
);
}
}
State
Class components can have state.
40. State Management
Component State
React provides simple state
management for each
component.
Centralised State
Redux is a centralised state
management system, often
simplifying your components
dramatically.
42. Components
class Clock extends React.Component {
// ...
componentDidMount() {
// called after the component is added to the DOM
this.timerID = setInterval(() => this.tick(), 1000);
}
componentWillUnmount() {
// called before the component is removed from the DOM
clearInterval(this.timerID);
}
tick() {
this.setState({ date: moment() });
}
// ...
}
Lifecycle
Props
43. Components
class Clock extends React.Component {
// ...
componentDidMount() {
// called after the component is added to the DOM
this.timerID = setInterval(() => this.tick(), 1000);
}
componentWillUnmount() {
// called before the component is removed from the DOM
clearInterval(this.timerID);
}
tick() {
this.setState({ date: moment() });
}
// ...
}
Lifecycle
Props
44. Components
class Clock extends React.Component {
// ...
componentDidMount() {
// called after the component is added to the DOM
this.timerID = setInterval(() => this.tick(), 1000);
}
componentWillUnmount() {
// called before the component is removed from the DOM
clearInterval(this.timerID);
}
tick() {
this.setState({ date: moment() });
}
// ...
}
Lifecycle
Props
45. Components
class Clock extends React.Component {
// ...
componentDidMount() {
// called after the component is added to the DOM
this.timerID = setInterval(() => this.tick(), 1000);
}
componentWillUnmount() {
// called before the component is removed from the DOM
clearInterval(this.timerID);
}
tick() {
this.setState({ date: moment() });
}
// ...
}
Lifecycle
Props
The lifecycle methods update the state.
51. // src/components/Clock.js
class Clock extends React.Component {
render() {
return (
<span>{this.state.date.format(this.props.dateFormat)}</span>
);
}
}
Clock.defaultProps = {
"dateFormat": 'MMMM Do YYYY, h:mm:ss'
};
// clock.js
ReactDOM.render(
<Clock />,
document.getElementById('clock')
);
ReactDOM.render(
<Clock dateFormat='h:mm:ss'/>,
document.getElementById('clock')
);
Components
Lifecycle
Props
Props are set when created and are immutable.
52. Component Types
Container
Fetches the application data
and composes the User
Interface out of Presentation
components.
Presentation
Takes the data from a Container
component and presents it to
the user.
86. Entry Point
Import
Context
Render
import IssueMacroContainer from '../containers/IssueMacroContainer';
let spaceKey = queryString.parse(location.search)["spaceKey"];
ReactDOM.render(<IssueMacroContainer
loadIssues={Issues.loadIssues(spaceKey)}/>,
document.getElementById("list-issues"));
87. Entry Point
Import
Context
Render
import IssueMacroContainer from '../containers/IssueMacroContainer';
let spaceKey = queryString.parse(location.search)["spaceKey"];
ReactDOM.render(<IssueMacroContainer
loadIssues={Issues.loadIssues(spaceKey)}/>,
document.getElementById("list-issues"));
88. import IssueMacroContainer from '../containers/IssueMacroContainer';
let spaceKey = queryString.parse(location.search)["spaceKey"];
ReactDOM.render(<IssueMacroContainer
loadIssues={Issues.loadIssues(spaceKey)}/>,
document.getElementById("list-issues"));
Entry Point
Import
Context
Render
89. import IssueMacroContainer from '../containers/IssueMacroContainer';
let spaceKey = queryString.parse(location.search)["spaceKey"];
ReactDOM.render(<IssueMacroContainer
loadIssues={Issues.loadIssues(spaceKey)}/>,
document.getElementById("list-issues"));
Entry Point
Import
Context
Render
An entry point will render the top component.
90. webpack takes modules with dependencies and
generates static assets representing those modules.
http://webpack.github.io/
114. Node JS
Uses NPM to package both server and client side
modules.
Manually Package
You can still use NPM to bundle your client side
components
Dev Loop
Restart your add-on service and call webpack on
each change.