6. Minimum Setup ES5
<script src="node_modules/react/dist/react.js"></script>
<script src="node_modules/react-dom/dist/react-dom.js"></script>
<script src=“https://cdnjs.cloudflare.com/ajax/libs/babel-core/5.8.34/browser.min.js">
script>
<body>
<div id="example"></div>
<script type="text/babel">
ReactDOM.render(
);
</script>
</body>
<h1>Hello, world!</h1>,
document.getElementById('example')
Where to render
the appContent
7. JSX
Syntax extension to javascript
const element = <h1>Hello, world!</h1>;
Allows us to do things like:
Needs to be transpiled :
const element = (
<h1 className="greeting">
Hello, world!
</h1>
);
JSX
const element = React.createElement(
'h1',
{className: 'greeting'},
'Hello, world!'
);
ES5
JSX is your friend, you don’t have to use it
HTML in my javascript!!
12. Component with data
let data = {
name : 'chris',
profession : 'software developer',
skills : ['.net', 'javascript', 'angular', 'react']
}
This is what we want to render
looks like a property
looks like a list
ReactDOM.render(
<App data={ data } />,
document.getElementById('example')
);
property = { variable }
Access data inside component like this:
var App = React.createClass({
render: function() {
return (
<div> { this.props.data.name } </div>
);
}
});
this.props.data.name
“chris”
13. Rendering a list
var App = React.createClass({
render: function() {
return (
<div>
<div> { this.props.data.name } </div>
<div>{ skills }</div>
</div>
);
}
});
let skills = this.props.data.skills.map(skill => {
return (
<div className="skill">{skill}</div>
);
});
Projection
Interpolation
Everything is in the “App” component = BAD
14. Refactoring
Putting everything in the App component isn’t very “react like”
of us
var App = React.createClass({
render: function() {
return (
<CV data={ this.props.data } />
);
}
});
var CV = React.createClass({
render: function() {
return (
<div className="cv">
{ this.data.props.name }
<Skills data={ this.data.props.skills } >
</div>
);
}
});
var Skills = React.createClass({
render : function(){
var skills = this.props.data.map(function(skill) {
return (
<div className="skill">{skill}</div>
);
});
return(
<div className="skills">
<h2>Skills</h2>
{ skills }
</div>
);
}
})
15. We can do this even better
var Skills = React.createClass({
render : function(){
var skills = this.props.data.map(function(skill) {
return (
<Skill data={ skill } />
);
});
return(
<div className="skills">
<h2>Skills</h2>
{ skills }
</div>
);
}
})
var Skill = React.createClass({
render : function(){
return(
<div className="skills">
<h3>{ this.props.data }</h3>
</div>
);
}
})
A component should do one thing well
One Skill comp
per skill item
20. Component State
var App = React.createClass({
getInitialState : function() {
return {
a : ‘some state’
};
},
render : function() {
return <div>{ this.state.a }</div>
}
});
Reading state
getInitialState is read
once per bootstrap,
define your state here
this.state.<prop>
21. Changing state
var App = React.createClass({
getInitialState : function() {
return {
newSkill : ‘some state’,
b : ‘some other state’
};
},
render : function() {
return <div>
<input value={this.state.newSkill} >
{ this.state.a }
</div>
}
For every change
of input field
update state
onChange={this.onSkillChange}
bind to onchange
onSkillChange : function(e){
this.setState({newSkill : e.target.value});
}
29. We want to write in ES6 cause it has nice features
Object.assign() Let Const
Spread Operator Lambdas
ES6 modules
import {} from ‘’
export default
export { a,b,c }
30. ES6 component
class Todo extends React.Component {
constructor(){
super();
this.action = this.action.bind(this);
this.state.prop = value
}
render() {
return (
<div onClick={this.action}>{this.props.title}</div>
)
}
action(e){
this.props.click( this.props.id );
}
}
GOTCHA, we need to call the following,
for our methods to be picked up
We inherit from React.Component
instead of
calling React.createClass({})
Otherwise its business as usual
we DON’t use getInitialState(){}
we just set this.state in constructor
We create a proper class
rather than an object literal
32. Catch bugs with type checking
Will give an error in a tool,
wrong type
Component.propTypes ={
title : React.PropTypes.string
}
<Component title=1 >
Example 1 - wrong type
Component.propTypes ={
title : React.PropTypes.string.isRequired
}
Example 2 - required
<Component > Will giver error, prop missing
33. Many validation types
oneOfType oneOf
arrayOf
objectOf
element instanceOf
symbol
custom
Further reading, https://facebook.github.io/react/docs/
typechecking-with-proptypes.html
35. Action describes what
should happen with what data
Action
Dispatcher
Store
React e.g. Add todo
Store notifies listener that data
has changed and needs to be reread
Dispatch action to store, tell the store
Unidirectional flow, everything flows in one direction
39. var Todos = React.createClass({
getInitialState : function(){
return { todos : Store.getTodos() }
}
render : function(){
return ([ render todos ])
},
})
//todos-component.js
componentDidMount : function(){
Store.addChangeListener( this._onChange )
},
componentWillUnmount : function(){
Store.removeChangeListener( this._onChange )
},
onChange() {
this.setState({ todos : Store.getTodos() })
}
Get data
1
Update state
so render() is called
2
40. store.js
var todos = [];
function loadTodos(){ return todos; }
var Store = merge(EventEmitter.prototype, {
getTodos : function(){ return todos; }
emitChange : function(){ emit(‘change’) },
addChangeListener : function(callback){ this.on(‘change’, callback) },
removeChangeListener : function(callback) { this.removeListener(‘change’, callback) }
})
Dispatcher.register(function(payload){
var action = payload.action;
switch(action) {
case ADD_TODO: todos.push( payload.data )
case LOAD_TODOS: loadTodos();
}
Store.emitChange();
})
Calls _onChange() on the component
Called when
Dispatcher.dispatch()
getData
addListener
removeListener
notifyChange
41. var AddTodo = React.createClass({
render : function(){
return ([ todo input ])
},
createTodo : function(todo){
Actions.addTodo( todo )
}
})
//add-todo-component.js
Calls the ActionCreator with a type and a payload
42. ActionCreator
Actions = {
addTodo : function(todo) {
Dispatcher.dispatch(
{ actionType : ADD_TODO, data : todo } )
}
…
}
Dispatch the action
56. Benefits to immutable state
Clarity answers - who changed that state?
Mutable, anyone could have changed it
Immutable, only a reducer could have changed it
Performance
No need to check every single property on an object
if(oldState != newState), reference check
Time travel debugging
57. State Summary
ES5
lodash merge
lodash extend
Object-assign ( NPM )
Reference checking
is super fast
Enables time-travel
debugging
through browser plugin
Object.assign()
… spread operator for arrays
ES6
Change state by
58. All Reducers are called on each dispatch
addItemReducer
removeItemReducer
listItemsReducer
Dispatching addItem
{ type: ADD_ITEM, : item : item }
returns new state
return state
return state
61. Connect store data to our
app
ComponentApp
Provider
Store Data
Setup our store
Wrap App component in a Provider
62. import { combineReducers } from 'redux';
import todos from './todo-reducer';
const rootReducer = combineReducers({
todos : todos
}) // OR todos only, LHS is implied
export default rootReducer;
reducers/index.js
Root reducer
Combines all reducers in one,
this is one we feed to the store
63. Initialise store
import { createStore, applyMiddleware } from 'redux';
import rootReducer from '../reducers' // index.js
import reduxImmutableStateInvariant from 'redux-immutable-state-invariant';
export default function configureStore(initialState) {
return createStore(
rootReducer,
initialState,
applyMiddleware( reduxImmutableStateInvariant() )
)
}
configure-store.js
Create store
give it a
root reducer
initial state
and add middleware
64. Provider
<Provider store={store} >
<App />
</Provider>
Uses Reacts context - don’t touch
import configureStore from './store/configureStore';
import { Provider } from 'ReactRedux';
Make your store available to all your components
65. Component
Wrap our component in a container
component using
Connect
Presentational
Component
Container component
export default connect(
mapStateToProps,
mapDispatchToProps
)( PresentationalComponent )
what state
what functions
66. what state should I expose as props
mapStateToProps
mapStateToProps = () => {
return {
appState : ‘’,
otherAppState : ‘’
}
}
// Component
this.props.appState
this.props.otherAppState
Every time a change happens this function is rerun, so don’t
do anything expensive in there
68. mapDispatchToProps - nicer
what actions do we want to expose to the component
mapDispatchToProps = () => {
return {
actions : bindActionCreators(actions, dispatch)
}
}
This is a shorthand using Redux
this.actions.methodName()
71. class TodoComponent extends React.Component{
onSave(){
this.props.dispatch(todoActions.addTodo(this.state.todo));
//console.log(this.state.todo.title);
}
}
function mapStateToProps(state, ownProps) {
return {
todos : state.todos
}
}
export default connect(
mapStateToProps)
(TodoComponent); 1
2
3
Reduxify your component in 3 steps
Decorate our Component
Expose state
Calling and dispatching
an action
72. Redux flow so far
Actions Dispatches an action
Reducers
current state + action =
new state
Store let connected components
know of state change
ReactRedux determine wether
to tell React to update UI
React new data passed
through props
YES
Something happenedReact
73. Redux concepts so far
Container and Presentation components
Has methods,
Has state,
Knows Redux
Just props
No Redux
ReactRedux
Provider Pass store data to Components
Connect
mapStateToProps Pass state and
methods to Components
mapDispatchToProps
83. export function loadTodos() {
return function(dispatch) {
return service.getTodos().then( todos => {
dispatch( loadTodosSuccess(todos) )
}).catch(error => { console.error(error) })
}
}
export function loadTodosSuccess(todos) {
return { type : types.LOAD_TODOS, todos : todos }
}
todo-actions.js
index.js
const store = configureStore();
store.dispatch( loadTodos() )
set initial data
Call dispatch
when Ajax is done
84. export default function todoReducer(
state = [], action) {
switch(action.type) {
…
case actionTypes.LOAD_TODOS :
return action.todos
default :
return state;
}
}
todo-reducer.js
85. Component
class TodoComponent extends React.Component{
render(){
let todos = this.state.todos.map( todo => {
return <div>{ todo }</div>
})
return ( <div>{ todos }</div> )
}
}
function mapStateToProps(state, ownProps) {
return {
todos : state.todos
}
}
export default connect(
mapStateToProps)
(TodoComponent);
86. Async load summary
Create async action that calls
dispatch when done
Add reducer for loading data
Add said reducer to rootReducer
store.dispatch( loadAction() ) in index.js
ensure its exposed in mapStateToProps
use in presentation component