React Hook
Introduction

You can use functional component everywhere.

Motivation

  • hard to reuse stateful logic between components

  • Complex components become hard to understand

  • Classes confuse both people and machines

Share Codes

import React from 'react'
import ReactDOM from 'react-dom'

const App = React.createClass({
  getInitialState() {
    return { x: 0, y: 0 }
  },

  handleMouseMove(event) {
    this.setState({
      x: event.clientX,
      y: event.clientY
    })
  },

  render() {
    const { x, y } = this.state

    return (
      <div style={{ height: '100%' }} onMouseMove={this.handleMouseMove}>
        <h1>The mouse position is ({x}, {y})</h1>
      </div>
    )
  }
})

ReactDOM.render(<App/>, document.getElementById('app'))

Share Codes via mixins

import React from 'react'
import ReactDOM from 'react-dom'

const MouseMixin = {
  getInitialState() {
    return { x: 0, y: 0 }
  },

  handleMouseMove(event) {
    this.setState({
      x: event.clientX,
      y: event.clientY
    })
  }
}

const App = React.createClass({
  mixins: [ MouseMixin ],
  
  render() {
    const { x, y } = this.state

    return (
      <div style={{ height: '100%' }} onMouseMove={this.handleMouseMove}>
        <h1>The mouse position is ({x}, {y})</h1>
      </div>
    )
  }
})

ReactDOM.render(<App/>, document.getElementById('app'))

Share Codes via HOC

const hoc1 = (Component) => {
 return class extends React.Component {
   constructor(props) {
     super(props);
   }
   
   render() {
     return <Component {...this.props} {...this.state} />
   }
 };
}

Share Codes via Render Props

class Cat extends React.Component {
  render() {
    const mouse = this.props.mouse;
    return (
      <img src="/cat.jpg" style={{ position: 'absolute', left: mouse.x, top: mouse.y }} />
    );
  }
}

class Mouse extends React.Component {
  constructor(props) {
    super(props);
    this.handleMouseMove = this.handleMouseMove.bind(this);
    this.state = { x: 0, y: 0 };
  }

  handleMouseMove(event) {
    this.setState({
      x: event.clientX,
      y: event.clientY
    });
  }

  render() {
    return (
      <div style={{ height: '100%' }} onMouseMove={this.handleMouseMove}>

        {/*
          Instead of providing a static representation of what <Mouse> renders,
          use the `render` prop to dynamically determine what to render.
        */}
        {this.props.render(this.state)}
      </div>
    );
  }
}

class MouseTracker extends React.Component {
  render() {
    return (
      <div>
        <h1>Move the mouse around!</h1>
        <Mouse render={mouse => (
          <Cat mouse={mouse} />
        )}/>
      </div>
    );
  }
}

You can use
React Hook Now! 

Class "this" confusing problem

'use strict';
class Clicker {
  constructor(element) {
    this.count = 0;
    this.elem = element;
    this.elem.addEventListener('click', this.click);
    
    // logs Clicker { count:0, elem: button#thing} as expected
    console.log(this);
  }

  click() {
    // logs <button id="thing">...</button> as unexpected...
    console.log(this);
    this.count++;
  }
}


var thing = document.getElementById('thing');
var instance = new Clicker(thing);

Class "this" confusing problem

// #1
this.elem.addEventListener('click', this.click.bind(this));

// #2
var self = this;
this.elem.addEventListener('click', function() {
    self.click();
});

// #3
this.elem.addEventListener('click', () => this.click());

Bad Part by using Class Syntax

  • The concept of "Class" doesn’t exist in JavaScript.
  • It guides people away from goodness and power of functional programming
  • Carefully use super in your class

What are Hooks

讓 functional compoment 可以使用或改變 state

useState

the current state value and a function that lets you update it.

import { useState } from 'react';

function Example() {
  // Declare a new state variable, which we'll call "count"
  const [count, setCount] = useState(0);

  return (
    <div>
      <p>You clicked {count} times</p>
      <button onClick={() => setCount(count + 1)}>
        Click me
      </button>
    </div>
  );
}

useState

the current state value and a function that lets you update it.

function ExampleWithManyStates() {
  // Declare multiple state variables!
  const [age, setAge] = useState(42);
  const [fruit, setFruit] = useState('banana');
  const [todos, setTodos] = useState([{ text: 'Learn Hooks' }]);
  // ...
}

useEffect

DOM operation side effect

import { useState, useEffect } from 'react';

function Example() {
  const [count, setCount] = useState(0);

  // Similar to componentDidMount and componentDidUpdate:
  useEffect(() => {
    // Update the document title using the browser API
    document.title = `You clicked ${count} times`;
  });

  return (
    <div>
      <p>You clicked {count} times</p>
      <button onClick={() => setCount(count + 1)}>
        Click me
      </button>
    </div>
  );
}

useEffect

Cleaner Listener, Subscription...etc

import { useState, useEffect } from 'react';

function FriendStatus(props) {
  const [isOnline, setIsOnline] = useState(null);

  function handleStatusChange(status) {
    setIsOnline(status.isOnline);
  }

  useEffect(() => {
    ChatAPI.subscribeToFriendStatus(props.friend.id, handleStatusChange);

    return () => {
      ChatAPI.unsubscribeFromFriendStatus(props.friend.id, handleStatusChange);
    };
  });

  if (isOnline === null) {
    return 'Loading...';
  }
  return isOnline ? 'Online' : 'Offline';
}

useContext

Better using Context API

<FooContext.Consumer>
  {foo => (
    <BarContext.Consumer>
      {bar => (
        <BazContext.Consumer>
          {baz => (
            <Component />
          )}
        </BazContext.Consumer>
      )}
    </BarContext.Consumer>
  )}
</FooContext.Consumer>
const fooContext = useContext(FooContext);

Custom Hook

import { useState, useEffect } from 'react';

function useFriendStatus(friendID) {
  const [isOnline, setIsOnline] = useState(null);

  function handleStatusChange(status) {
    setIsOnline(status.isOnline);
  }

  useEffect(() => {
    ChatAPI.subscribeToFriendStatus(friendID, handleStatusChange);
    return () => {
      ChatAPI.unsubscribeFromFriendStatus(friendID, handleStatusChange);
    };
  });

  return isOnline;
}

Visual Result

https://twitter.com/prchdk/status/1056960391543062528

Demo

Javascript

ES6 Class

Object Model

Prototypal inheritance

1. prototype of prototype

2. Python instance dictionary and class dictionary

Internal slots

1. internal method and internal slots

2. Object.getPrototypeOf()
3. Object.setPrototypeOf()

Olded style classes


function Foo(x) {
    this.x = x;
    this.y = 432;
}
Foo.prototype.point = function() {
    return `Foo ${this.x + this.y}`;
}

var myfoo = new Foo(99);
console.log(myfoo.point());

Function in Javascript

[[Call]]
[[Construct]]

Prototype Diagram in Foo

ES6 Class Syntax

class Foo {
    constructor(x) {
        this.x = x;
        this.y = 432;
    }

    point() {
        return `Foo ${this.x} + ${this.y}`;
    }
}

let myfoo = new Foo(99);
console.log(myfoo.point());

ES6 Class Syntax

class Base {
    foo() {return 'foo in Base';}
    bar() {return 'bar in Base';}
}
class Child extends Base {
    foo() {return 'foo in Child';}
    whiz() {return 'whiz in Child';}
}

const b = new Base;
const c = new Child;

console.log(b.foo()); // foo in Base
console.log(b.bar()); // bar in Base
console.log(c.foo()); // foo in Child
console.log(c.bar()); // bar in Base
console.log(c.whiz()); // whiz in Child

Prototype Diagram in Base and Child 

Not Using ES6 Class syntax


function Base() {}
Base.prototype.foo = function() {return 'foo in Base';};
Base.prototype.bar = function() {return 'bar in Base';};

function Child() {}
Object.setPrototypeOf(Child, Base);
Object.setPrototypeOf(Child.prototype, Base.prototype);
Child.prototype.foo = function() {return 'foo in Child';};
Child.prototype.whiz = function() {return 'whiz in Child';};


var b = new Base;
var c = new Child;

console.log(b.foo()); // foo in Base
console.log(b.bar()); // bar in Base
console.log(c.foo()); // foo in Child
console.log(c.bar()); // bar in Base
console.log(c.whiz()); // whiz in Child

Superclass property access

1. calling a superclass constructor
2.
accessing properties of the superclass.

Superclass property access

class A {
    foo() {return 'foo in A';}
}
class B extends A {
    foo() {return 'foo in B';}
}
class C {
    foo() {return 'foo in C';}
}
class D extends C {
    foo() {return super.foo();}
}

b = new B;
console.log(b.foo()); // foo in B

B.prototype.foo = D.prototype.foo
console.log(b.foo()); // foo in C
console.log(b instanceof C); // false

React Hook Introdunction

By Stanney Yen

React Hook Introdunction

  • 249