13/04/2019 reveal.js
localhost:8000/?print-pdf 1/19
REACT HOOKS ⚓REACT HOOKS ⚓Felix Kühl - JobMatchMe GmbH
13/04/2019 reveal.js
localhost:8000/?print-pdf 2/19
INTRODUCTION TO HOOKSINTRODUCTION TO HOOKS
statefull component
useState
class NameInput extends React.Component {
constructor(){
state = { name: "Max" }
}
handleChange = (e) => {
this.setState({name: e.target.value})
}
render(){ return <input type="text" onChange={this.handleChange} value={this.state} /> }
}
const NameInput = () => {
const [name, setName] = useState("Max")
const handleChange = (e) => {
setName(e.target.value)
}
return <input type="text" onChange={handleChange} value={name} />
}
13/04/2019 reveal.js
localhost:8000/?print-pdf 3/19
WHY USESTATE IS ACUTALLYWHY USESTATE IS ACUTALLY
AWESOMEAWESOME
const Parent = () => {
const [name, setName] = useState()
return <Child setParentState={setName} />
}
const Child = ({setParentState}) => {
const upperCaseMe = () => {
setParentState((state) => state.toUpperCase())
})
return <button onClick={upperCaseMe}>Upper case my name!</button>
}
13/04/2019 reveal.js
localhost:8000/?print-pdf 4/19
INTRODUCTION TO HOOKSINTRODUCTION TO HOOKS
componentDidMount & componentDidUpdate
class TitleInput extends React.Component {
constructor(){
state = { title: "Hello" }
}
handleChange = (e) => {
this.setState({title: e.target.value})
}
componentDidMount() {
document.title = this.state.title
}
componentDidUpdate() {
document.title = this.state.title
}
render(){ return <input type="text" onChange={this.handleChange} value={this.state.title} /> }
}
13/04/2019 reveal.js
localhost:8000/?print-pdf 5/19
INTRODUCTION TO HOOKSINTRODUCTION TO HOOKS
useEffect
const TitleInput = () => {
const [title, setTitle] = useState("Hello")
const handleChange = (e) => {
setTitle.target.value)
}
useEffect(() => { document.title = title })
return <input type="text" onChange={handleChange} value={title} />
}
13/04/2019 reveal.js
localhost:8000/?print-pdf 6/19
INTRODUCTION TO HOOKSINTRODUCTION TO HOOKS
componentDidMount
class WidthComponent extends React.Component {
constructor(){
state = { width: window.innerWidth }
}
handleResize = () => {
this.setState({width: window.innerWidth})
}
componentDidMount() {
window.addEventListener('resize', this.handleResize)
}
componentWillUnmount() {
window.removeEventListener('resize', this.handleResize)
}
render(){ return <p>{this.state.width}</p> }
}
13/04/2019 reveal.js
localhost:8000/?print-pdf 7/19
INTRODUCTION TO HOOKSINTRODUCTION TO HOOKS
useEffect
const WidthComponent = () => {
const [width, setWidth] = useState(window.innerWidth)
const handleResize = () => {
setWidth(window.innerWidth)
}
useEffect(() => {
window.addEventListener('resize', handleResize)
return window.removeEventListener('resize', handleResize)
}, [])
return <p>{width}</p>
}
13/04/2019 reveal.js
localhost:8000/?print-pdf 8/19
INTRODUCTION TO HOOKSINTRODUCTION TO HOOKS
And what about componentDidUpdate?
13/04/2019 reveal.js
localhost:8000/?print-pdf 9/19
INTRODUCTION TO HOOKSINTRODUCTION TO HOOKS
And what about componentDidUpdate?
useEffect(() => { if(iMightChange !== null) { doSomething() } }, [iMightChange])
13/04/2019 reveal.js
localhost:8000/?print-pdf 10/19
INTRODUCTION TO HOOKSINTRODUCTION TO HOOKS
useContext
const Consumer = () => {
const value = useContext()
return (
<Context.Consumer>
{value => <p>Context says {value}</p>}
</Context.Consumer>
)
}
const Consumer = () => {
const value = useContext()
return (
<p>Context says {value}</p>
)
}
13/04/2019 reveal.js
localhost:8000/?print-pdf 11/19
INTRODUCTION TO HOOKSINTRODUCTION TO HOOKS
useMemo
const memoizedValue = useMemo(() => someExpensiveCalculation(x, y), [x, y]);
13/04/2019 reveal.js
localhost:8000/?print-pdf 12/19
REUSE AND COMPOSEREUSE AND COMPOSE
Are hooks kind of like mixins
const MyLocation = () => {
const location = useLocation()
return <p>You are at: {location}</p>
}
const useLocation = () => {
const [location, setLocation] = useState("loading...")
useEffect(() => {
if (navigator.geolocation) {
navigator.geolocation.getCurrentPosition(() =>
setLocation("lat: "+position.coords.latitude+" lng: "+position.coords.longitude)
);
} else {
return "Geolocation is not supported by this browser.";
}
})
return location
}
13/04/2019 reveal.js
localhost:8000/?print-pdf 13/19
HOOKS IN REAL LIFEHOOKS IN REAL LIFE
Our (old) data provider
/* Context */
const DataContext = React.createContext()
/**
* Global user data provider
*
**/
class DataProvider extends React.Component {
constructor(props) {
super(props)
this.state = {
status: 'init',
data: parseData({}),
actions: {fetchData: this.fetchData}
}
}
/**
* Fetch Data only when we are authenticated. This might not happen on initial mounting
/
13/04/2019 reveal.js
localhost:8000/?print-pdf 14/19
HOOKS IN REAL LIFEHOOKS IN REAL LIFE
... now with hooks! ✨
/* Context */
export const DataContext = React.createContext()
/**
* Data Reducer
*/
const reducer = (state, action) => { ... }
/**
* Global user data provider
*
**/
const DataProvider = props => {
/**
* Fetch Data from API endpoint
*/
const fetchData = async () => { ... }
const [state, dispatch] = useReducer(reducer, {
'i i '
13/04/2019 reveal.js
localhost:8000/?print-pdf 15/19
HOOKS IN REAL LIFEHOOKS IN REAL LIFE
Class vs Hooks
async componentDidMount() {
if (this.props.authState === 'signedIn') {
await this.fetchData()
}
}
async componentDidUpdate(prevProps, prevState) {
if (
prevProps.authState !== this.props.authState &&
this.props.authState === 'signedIn'
) {
await this.fetchData()
}
}
useEffect(() => {
if (props.authState === 'signedIn') {
fetchData()
}
}, [props.authState])
13/04/2019 reveal.js
localhost:8000/?print-pdf 16/19
HOOKS UNDER THE HOODHOOKS UNDER THE HOOD
react / packages / react-reconciler / src / ReactFiberHooks.js
// TODO: Not sure if this is the desired semantics, but it's what we
// do for gDSFP. I can't remember why.
if (workInProgressHook.baseUpdate === queue.last) {
workInProgressHook.baseState = newState;
}
...
13/04/2019 reveal.js
localhost:8000/?print-pdf 17/19
HOOKS UNDER THE HOODHOOKS UNDER THE HOOD
https://medium.com/the-guild/under-the-hood-of-reacts-hooks-system-eb59638c9dba
13/04/2019 reveal.js
localhost:8000/?print-pdf 18/19
HOOKS UNDER THE HOODHOOKS UNDER THE HOOD
State object
State hooks queue
{
foo: 'foo',
bar: 'bar',
baz: 'baz',
}
{
memoizedState: 'foo',
next: {
memoizedState: 'bar',
next: {
memoizedState: 'bar',
next: null
}
}
}
13/04/2019 reveal.js
localhost:8000/?print-pdf 19/19
FINAL THOUGHTSFINAL THOUGHTS

Deep Dive into React Hooks

  • 1.
    13/04/2019 reveal.js localhost:8000/?print-pdf 1/19 REACTHOOKS ⚓REACT HOOKS ⚓Felix Kühl - JobMatchMe GmbH
  • 2.
    13/04/2019 reveal.js localhost:8000/?print-pdf 2/19 INTRODUCTIONTO HOOKSINTRODUCTION TO HOOKS statefull component useState class NameInput extends React.Component { constructor(){ state = { name: "Max" } } handleChange = (e) => { this.setState({name: e.target.value}) } render(){ return <input type="text" onChange={this.handleChange} value={this.state} /> } } const NameInput = () => { const [name, setName] = useState("Max") const handleChange = (e) => { setName(e.target.value) } return <input type="text" onChange={handleChange} value={name} /> }
  • 3.
    13/04/2019 reveal.js localhost:8000/?print-pdf 3/19 WHYUSESTATE IS ACUTALLYWHY USESTATE IS ACUTALLY AWESOMEAWESOME const Parent = () => { const [name, setName] = useState() return <Child setParentState={setName} /> } const Child = ({setParentState}) => { const upperCaseMe = () => { setParentState((state) => state.toUpperCase()) }) return <button onClick={upperCaseMe}>Upper case my name!</button> }
  • 4.
    13/04/2019 reveal.js localhost:8000/?print-pdf 4/19 INTRODUCTIONTO HOOKSINTRODUCTION TO HOOKS componentDidMount & componentDidUpdate class TitleInput extends React.Component { constructor(){ state = { title: "Hello" } } handleChange = (e) => { this.setState({title: e.target.value}) } componentDidMount() { document.title = this.state.title } componentDidUpdate() { document.title = this.state.title } render(){ return <input type="text" onChange={this.handleChange} value={this.state.title} /> } }
  • 5.
    13/04/2019 reveal.js localhost:8000/?print-pdf 5/19 INTRODUCTIONTO HOOKSINTRODUCTION TO HOOKS useEffect const TitleInput = () => { const [title, setTitle] = useState("Hello") const handleChange = (e) => { setTitle.target.value) } useEffect(() => { document.title = title }) return <input type="text" onChange={handleChange} value={title} /> }
  • 6.
    13/04/2019 reveal.js localhost:8000/?print-pdf 6/19 INTRODUCTIONTO HOOKSINTRODUCTION TO HOOKS componentDidMount class WidthComponent extends React.Component { constructor(){ state = { width: window.innerWidth } } handleResize = () => { this.setState({width: window.innerWidth}) } componentDidMount() { window.addEventListener('resize', this.handleResize) } componentWillUnmount() { window.removeEventListener('resize', this.handleResize) } render(){ return <p>{this.state.width}</p> } }
  • 7.
    13/04/2019 reveal.js localhost:8000/?print-pdf 7/19 INTRODUCTIONTO HOOKSINTRODUCTION TO HOOKS useEffect const WidthComponent = () => { const [width, setWidth] = useState(window.innerWidth) const handleResize = () => { setWidth(window.innerWidth) } useEffect(() => { window.addEventListener('resize', handleResize) return window.removeEventListener('resize', handleResize) }, []) return <p>{width}</p> }
  • 8.
    13/04/2019 reveal.js localhost:8000/?print-pdf 8/19 INTRODUCTIONTO HOOKSINTRODUCTION TO HOOKS And what about componentDidUpdate?
  • 9.
    13/04/2019 reveal.js localhost:8000/?print-pdf 9/19 INTRODUCTIONTO HOOKSINTRODUCTION TO HOOKS And what about componentDidUpdate? useEffect(() => { if(iMightChange !== null) { doSomething() } }, [iMightChange])
  • 10.
    13/04/2019 reveal.js localhost:8000/?print-pdf 10/19 INTRODUCTIONTO HOOKSINTRODUCTION TO HOOKS useContext const Consumer = () => { const value = useContext() return ( <Context.Consumer> {value => <p>Context says {value}</p>} </Context.Consumer> ) } const Consumer = () => { const value = useContext() return ( <p>Context says {value}</p> ) }
  • 11.
    13/04/2019 reveal.js localhost:8000/?print-pdf 11/19 INTRODUCTIONTO HOOKSINTRODUCTION TO HOOKS useMemo const memoizedValue = useMemo(() => someExpensiveCalculation(x, y), [x, y]);
  • 12.
    13/04/2019 reveal.js localhost:8000/?print-pdf 12/19 REUSEAND COMPOSEREUSE AND COMPOSE Are hooks kind of like mixins const MyLocation = () => { const location = useLocation() return <p>You are at: {location}</p> } const useLocation = () => { const [location, setLocation] = useState("loading...") useEffect(() => { if (navigator.geolocation) { navigator.geolocation.getCurrentPosition(() => setLocation("lat: "+position.coords.latitude+" lng: "+position.coords.longitude) ); } else { return "Geolocation is not supported by this browser."; } }) return location }
  • 13.
    13/04/2019 reveal.js localhost:8000/?print-pdf 13/19 HOOKSIN REAL LIFEHOOKS IN REAL LIFE Our (old) data provider /* Context */ const DataContext = React.createContext() /** * Global user data provider * **/ class DataProvider extends React.Component { constructor(props) { super(props) this.state = { status: 'init', data: parseData({}), actions: {fetchData: this.fetchData} } } /** * Fetch Data only when we are authenticated. This might not happen on initial mounting /
  • 14.
    13/04/2019 reveal.js localhost:8000/?print-pdf 14/19 HOOKSIN REAL LIFEHOOKS IN REAL LIFE ... now with hooks! ✨ /* Context */ export const DataContext = React.createContext() /** * Data Reducer */ const reducer = (state, action) => { ... } /** * Global user data provider * **/ const DataProvider = props => { /** * Fetch Data from API endpoint */ const fetchData = async () => { ... } const [state, dispatch] = useReducer(reducer, { 'i i '
  • 15.
    13/04/2019 reveal.js localhost:8000/?print-pdf 15/19 HOOKSIN REAL LIFEHOOKS IN REAL LIFE Class vs Hooks async componentDidMount() { if (this.props.authState === 'signedIn') { await this.fetchData() } } async componentDidUpdate(prevProps, prevState) { if ( prevProps.authState !== this.props.authState && this.props.authState === 'signedIn' ) { await this.fetchData() } } useEffect(() => { if (props.authState === 'signedIn') { fetchData() } }, [props.authState])
  • 16.
    13/04/2019 reveal.js localhost:8000/?print-pdf 16/19 HOOKSUNDER THE HOODHOOKS UNDER THE HOOD react / packages / react-reconciler / src / ReactFiberHooks.js // TODO: Not sure if this is the desired semantics, but it's what we // do for gDSFP. I can't remember why. if (workInProgressHook.baseUpdate === queue.last) { workInProgressHook.baseState = newState; } ...
  • 17.
    13/04/2019 reveal.js localhost:8000/?print-pdf 17/19 HOOKSUNDER THE HOODHOOKS UNDER THE HOOD https://medium.com/the-guild/under-the-hood-of-reacts-hooks-system-eb59638c9dba
  • 18.
    13/04/2019 reveal.js localhost:8000/?print-pdf 18/19 HOOKSUNDER THE HOODHOOKS UNDER THE HOOD State object State hooks queue { foo: 'foo', bar: 'bar', baz: 'baz', } { memoizedState: 'foo', next: { memoizedState: 'bar', next: { memoizedState: 'bar', next: null } } }
  • 19.