I'm Luke
@luke_dot_js
lukewestby
luke.westby@raise.com
+ Redux
// TODO:
- Explain React
- Explain Redux
- Set up a project
- Build an app
React
Virtual DOM
+
One-way Data Flow
<Components />
import React, { Component, PropTypes } from 'react';
export default class Greeter extends Component {
static propTypes = {
name: PropTypes.string.isRequired
};
state = {
currentSeconds: 0,
timeout: null
};
componentDidMount() {
const timeout = setTimeout(() => {
this.setState({
currentSeconds: this.state.currentSeconds + 1
});
}, 1000);
this.setState({ timeout });
}
componentWillUnmount() {
clearTimeout(this.state.timeout);
}
render() {
return (
<div>
<p>Hello, {this.props.name}!</p>
<p>{this.state.currentSeconds} have elapsed</p>
</div>
);
}
}
import React from 'react';
import Greeter from './Greeter';
React.render(
<Greeter name="JS.Chi" />,
document.querySelector('main')
);
React Key Concepts
- Props
- Immutable, passed in
- State
- Mutable, internal
- Rendering
- Pure functions
- Return a React Component (Virtual DOM)
- Frequently implemented with JSX
- Lifecycle Hooks
- Do manual setup/teardown
- Control updating
Redux
- One state container
- State is only mutable by actions
- Mutations are pure functions
// actions.js
export const INCREMENT_COUNT = 'INCREMENT_COUNT';
export function incrementCount(value) {
return { type: INCREMENT_COUNT, value };
}
export const DECREMENT_COUNT = 'DECREMENT_COUNT';
export function decrementCount(value) {
return { type: DECREMENT_COUNT, value };
}
// reducers.js
import { combineReducers } from 'redux';
import {
INCREMENT_COUNT,
DECREMENT_COUNT
} from './actions.js';
function count(count = 0, action) {
switch(action.type) {
case INCREMENT_COUNT:
return count + action.value;
case DECREMENT_COUNT:
return count - action.value;
default:
return count;
}
}
export default combineReducers({
count
});
// app.js
import React, { Component } from 'react';
import { createStore } from 'redux';
import { connect, Provider } from 'react-redux';
import {
incrementCount,
decrementCount
} from './actions';
import appReducer from './reducers';
@connect((store) => store)
class App extends Component {
render() {
const { count, dispatch } = this.props;
return (
<div>
<span>{count}</span>
<button onClick={() => dispatch(incrementCount(1))}>+1</button>
<button onClick={() => dispatch(decrementCount(1))}>-1</button>
</div>
);
}
}
const appStore = createStore(appReducer);
React.render(
<Provider store={appStore}>
{() => <App />}
</Provider>,
document.querySelector('main')
);
Other concerns
- Build
- Babel
- Webpack, Browserify + Gulp, etc.
- Server rendering
-
React.renderToString()
-
- Styling
- CSS Modules
- Stilr, Radium, etc.
- Testing
-
React.addons.TestUtils
-
jsdom
- Any test runner
-
Demo
App
Header
CommentsList
CommentBox
Comment
Comment
JS.Chi React Demo
By lukewestby
JS.Chi React Demo
Demonstration of building a React application start-to-finish for the Chicago JavaScript Meetup on August 25, 2015
- 1,531