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
- 262