React
Workshop
Setup
Workshop Projekt
git clone ssh://git@git.konform.com:7999/~jh/react-workshop.git
cd react-workshop
yarn install
# tilføj react-workshop.test til din /etc/hosts fil, hvis ikke du bruger dnsmasq
yarn start
# åbn http://react-workshop.test:3000/
# åbn i din editor
DevTools
Opgave 1
Basic Component
import React, { Component } from 'react';
import PropTypes from 'prop-types';
export default class ComponentName extends Component {
static propTypes = {
dispatch: PropTypes.func.isRequired,
};
static defaultProps = {};
constructor(props) {
super(props);
this.state = {
show: true,
};
}
render() {
return (
<div>
{this.state.show && (
<div className="thing">thing</div>
)}
</div>
);
}
}
import React from 'react';
import PropTypes from 'prop-types';
const ComponentName = (props) => (
<div>
{props.show && (
<div className="thing">thing</div>
)}
</div>
);
ComponentName.propTypes = {
show: PropTypes.bool
};
ComponentName.defaultProps = {
show: true,
};
export default ComponentName;import Box from '../../components/box';
import Sidebar from '../../components/sidebar';
const SIDEBAR_CONTENT = '../../constants/sidebarcontent';
const Main = () => (
<div className="container">
<Sidebar content={SIDEBAR_CONTENT} />
<div className="container__content">
<Box>Baz</Box>
</div>
</div>
);
export default Main;JSX
# loop
<ol>
{this.props.users.map((user) => (
<li>{user.name}</li>
))}
</ol># javascript
<div>
{this.getUsers()}
</div># conditional content
<div>
{!!this.state.users.length && (
<ol>
{this.props.users.map((user) => (
<li>{user.name}</li>
))}
</ol>
)}
</div>
# eller
<div>
{this.state.users.length ? (
<ol>
{this.props.users.map((user) => (
<li>{user.name}</li>
))}
</ol>
) : <div>Ingen brugere fundet</div>}
</div>HTML: "kebab-case"
JSX: "camelCase"
Fordi "class" er et reserved word i JS, hedder attributten className.
(Ligesom i DOM)
Attributes
# attributes
<input
type="text"
name={this.props.name}
name={this.props.placeholder}
tabIndex={this.props.tabIndex ? this.props.tabIndex : '-1'}
/>
# events
<button onClick={this.updateUserList}>
Update users
</button>class Thing extends Component {
render() {
return (
<button onClick={this.updateUserList.bind(this)}>
Update users
</button>
);
}
}class Thing extends Component {
render() {
return (
<button onClick={this.updateUserList}>
Update users
</button>
);
}
updateUserList = () => {
// ...
}
}Lifecycle methods
- mounting
- updating
- unmounting
- errors
Mounting
constructor(props) {
super(props);
this.state = {
color: props.initialColor
};
}
componentWillMount() {}
render() {}
componentDidMount() {}
Updating
componentWillReceiveProps(nextProps) {
// componenten har fået nye props (nextProps)
// de gamle props kan stadig tilgås via this.props
// hvis man har state der skal ændres baseret på props
// så kan det gøres nu
// kald til setState skipper denne
// nextProps kan godt være det samme som this.props
}
shouldComponentUpdate(nextProps, nextState) {
// "should" indikerer at den forventer en boolean return
// anvendes til at optimere sine renders,
// ved false skipper man render
}
componentWillUpdate(nextProps, nextState) {
// shouldComponentUpdate returnerede true så komponenten skal opdateres
// setState kan IKKE kaldes her
}
render() {}
componentDidUpdate(prevProps, prevState) {
// componenten blev re-rendered
// et godt sted
}
Unmounting
componentWillUnmount() {
// componenten er ved blive fjernet fra DOM'en
// bruges hvis der er brugerinput eller lignenede leftover
// så er dette en chance for fx at gemme inden indholdet slettes
}Errors
componentDidCatch(error, info) {}Opgave 2 + 3
Redux

this.props.dispatch({
type: 'ACTION_USERS_FETCHED',
data: {
users: [...],
},
});import { ACTION_ADD, ACTION_REMOVE } from '../constants/actions/demo';
const defaultState = {
count: 0,
};
function modifyByAmount(state, amount) {
return {
...state,
count: state.count + amount,
};
}
function increase(state) {
return modifyByAmount(state, 1);
}
function decrease(state) {
return modifyByAmount(state, -1);
}
export default function demoReducer(state = defaultState, action) {
switch (action.type) {
case ACTION_ADD:
return increase(state);
case ACTION_REMOVE:
return decrease(state);
default:
return state;
}
}
import { connect } from 'react-redux';
@connect((state) => ({
dispatch: state.dispatch,
dataFromStore: state.example.data,
}))
export default class Example extends Component {
}Opgave 4+
DONE
Så er der VR!

Workshop
By Jakob Hyldtoft
Workshop
- 532