Live replay link: Yunqi Community ( @-the X-Cold )
What React Hooks that?
Hooks As the name suggests, the literal sense is the concept React hook. Through a case we first have a first impression React Hooks.
Suppose now to implement components of a counter. When a component of the way, we need to do relatively more, such as declarations state, ways of writing a counter, etc., and may be more concept to understand some of the concepts such as Javascript class, this context points, etc. .
import React, { Component } from 'react';
import ReactDOM from 'react-dom';
class Counter extends React.Component {
state = {
count: 0
}
countUp = () => {
const { count } = this.state;
this.setState({ count: count + 1 });
}
countDown = () => {
const { count } = this.state;
this.setState({ count: count - 1 });
}
render() {
const { count } = this.state;
return (
<div>
<button onClick={this.countUp}>+</button>
<h1>{count}</h1>
<button onClick={this.countDown}>-</button>
</div>
)
}
}
ReactDOM.render(<Counter />, document.getElementById('root'));
复制代码
Use React Hooks, so we can write.
import React, { useState } from 'react';
import ReactDOM from 'react-dom';
function Counter() {
const [count, setCount] = useState(0);
return (
<div>
<button onClick={() => setCount(count + 1)}>+</button>
<h1>{count}</h1>
<button onClick={() => setCount(count - 1)}>-</button>
</div>
)
}
ReactDOM.render(<Counter />, document.getElementById('root'));
复制代码
By way of example above, it is obvious React Hooks provide a simple, functional style program (FP), and to interact (the MVVM) state to the UI by the pure components and functions controlled data stream.
Hooks API
useState
useState is the most basic API, which passed an initial value every time the function execution can get the new value.
import React, { useState } from 'react';
import ReactDOM from 'react-dom';
function Counter() {
const [count, setCount] = useState(0);
return (
<div>
<button onClick={() => setCount(count + 1)}>+</button>
<h1>{count}</h1>
<button onClick={() => setCount(count - 1)}>-</button>
</div>
)
}
ReactDOM.render(<Counter />, document.getElementById('root'));
复制代码
It should be noted, by state useState get the count, performance in Counter component is a constant, after each modified by setCount, again by useState to get a new constant.
useReducer
useReducer useState and almost the same, the reducer requires external external (global), multiple states can be controlled simultaneously in this manner. A closer look it, in fact with the concept of data streams redux is very close.
import { useState, useReducer } from 'react';
import ReactDOM from 'react-dom';
function reducer(state, action) {
switch (action.type) {
case 'up':
return { count: state.count + 1 };
case 'down':
return { count: state.count - 1 };
}
}
function Counter() {
const [state, dispatch] = useReducer(reducer, { count: 1 })
return (
<div>
{state.count}
<button onClick={() => dispatch({ type: 'up' })}>+</button>
<button onClick={() => dispatch({ type: 'down' })}>+</button>
</div>
);
}
ReactDOM.render(<Counter />, document.getElementById('root'));
复制代码
useEffect
A crucial Hooks API, as the name suggests, useEffect is used to treat side effects caused by changes in various states, meaning that only at a particular time, logic will be executed.
import { useState, useEffect } from 'react';
import ReactDOM from 'react-dom';
function Example() {
const [count, setCount] = useState(0);
// => componentDidMount/componentDidUpdate
useEffect(() => {
// update
document.title = `You clicked ${count} times`;
// => componentWillUnMount
return function cleanup() {
document.title = 'app';
}
}, [count]);
return (
<div>
<p>You clicked {count} times</p>
<button onClick={() => setCount(count + 1)}>
Click me
</button>
</div>
);
}
ReactDOM.render(<Example />, document.getElementById('root'));
复制代码
useMemo
useMemo mainly used to optimize the rendering process, two parameters are calculated sequentially function (typically a function of the component) and dependent status list, when dependent changes state to trigger the execution of the calculation function. If you do not specify a dependency, then each time the rendering process will perform this calculation functions.
const memoizedValue = useMemo(() => computeExpensiveValue(a, b), [a, b]);
复制代码
import { useState, useMemo } from 'react';
import ReactDOM from 'react-dom';
function Time() {
return <p>{Date.now()}</p>;
}
function Counter() {
const [count, setCount] = useState(0);
const memoizedChildComponent = useMemo((count) => {
return <Time />;
}, [count]);
return (
<div>
<h1>{count}</h1>
<button onClick={() => setCount(count + 1)}>+</button>
<div>{memoizedChildComponent}</div>
</div>
);
}
ReactDOM.render(<Counter />, document.getElementById('root'));
复制代码
useContext
context is externally create, internal use of the state, and it is the difference between global variables, if multiple components simultaneously useContext, then these components will rerender, if multiple components simultaneously useState same global variable, only the trigger of the current component setState rerender.
import { useState, useContext, createContext } from 'react';
import ReactDOM from 'react-dom';
// 1. 使用 createContext 创建上下文
const UserContext = new createContext();
// 2. 创建 Provider
const UserProvider = props => {
let [username, handleChangeUsername] = useState('');
return (
<UserContext.Provider value={{ username, handleChangeUsername }}>
{props.children}
</UserContext.Provider>
);
};
// 3. 创建 Consumer
const UserConsumer = UserContext.Consumer;
// 4. 使用 Consumer 包裹组件
const Pannel = () => (
<UserConsumer>
{({ username, handleChangeUsername }) => (
<div>
<div>user: {username}</div>
<input onChange={e => handleChangeUsername(e.target.value)} />
</div>
)}
</UserConsumer>
);
const Form = () => <Pannel />;
const App = () => (
<div>
<UserProvider>
<Form />
</UserProvider>
</div>
);
ReactDOM.render(<App />, document.getElementById('root'));
复制代码
import { useState, useContext, createContext } from 'react';
import ReactDOM from 'react-dom';
// 1. 使用 createContext 创建上下文
const UserContext = new createContext();
// 2. 创建 Provider
const UserProvider = props => {
let [username, handleChangeUsername] = useState('');
return (
<UserContext.Provider value={{ username, handleChangeUsername }}>
{props.children}
</UserContext.Provider>
);
};
const Pannel = () => {
const { username, handleChangeUsername } = useContext(UserContext); // 3. 使用 Context
return (
<div>
<div>user: {username}</div>
<input onChange={e => handleChangeUsername(e.target.value)} />
</div>
);
};
const Form = () => <Pannel />;
const App = () => (
<div>
<UserProvider>
<Form />
</UserProvider>
</div>
);
ReactDOM.render(<App />, document.getElementById('root'));
复制代码
useRef
useRef ref returns a variable object which .current property parameters passed initialized (initialValue). The returned object will last the entire life cycle of components. In fact useRef is a very useful API, in many cases, we need to keep some things change, it will come in handy in.
function TextInputWithFocusButton() {
const inputEl = useRef(null);
const onButtonClick = () => {
// `current` points to the mounted text input element
inputEl.current.focus();
};
return (
<>
<input ref={inputEl} type="text" />
<button onClick={onButtonClick}>Focus the input</button>
</>
);
}
复制代码
React state sharing scheme
Speaking state sharing, the simplest and most direct way is to cascade through props transmission state, this assembly coupled to a parent-child relationship, once the nested assembly configuration changes, it is necessary to re-write the code, the maintenance cost is very expensive. Over time, the official introduced a variety of programs to address the status code reuse and sharing of problems.
Mixins
React, only components created by createClass to use mixins. This high coupling dependence is difficult to control, as the wave of high complexity way ES6 gradually fade out the stage of history.
HOC
Higher order components from functional programming, because of React components may be considered as a function (s), thus can naturally be implemented by code reuse HOC manner. Properties may be achieved by agents and reverse succession, HOC can easily control the rendering result may be operated assembly props / state, so that the complex can easily reuse code logic.
import React from 'react';
import PropTypes from 'prop-types';
// 属性代理
class Show extends React.Component {
static propTypes = {
children: PropTypes.element,
visible: PropTypes.bool,
};
render() {
const { visible, children } = this.props;
return visible ? children : null;
}
}
// 反向继承
function Show2(WrappedComponent) {
return class extends WrappedComponent {
render() {
if (this.props.visible === false) {
return null;
} else {
return super.render();
}
}
}
}
function App() {
return (
<Show visible={Math.random() > 0.5}>hello</Show>
);
}
复制代码
Redux state in multiplexing HOC is a typical implementation, we can be assembled to compose the data through the target component, of course, you can also be treated by the decorator manner.
import React from 'react';
import { connect } from 'react-redux';
// use decorator
@connect(state => ({ name: state.user.name }))
class App extends React.Component{
render() {
return <div>hello, {this.props.name}</div>
}
}
// use compose
connect((state) => ({ name: state.user.name }))(App);
复制代码
Render Props
Apparent, renderProps A is transferred to the render method as props subassembly embodiment, compared with the HOC embodiment, renderProps protect existing component hierarchy.
import React from 'react';
import ReactDOM from 'react-dom';
import PropTypes from 'prop-types';
// 与 HOC 不同,我们可以使用具有 render prop 的普通组件来共享代码
class Mouse extends React.Component {
static propTypes = {
render: PropTypes.func.isRequired
}
state = { x: 0, y: 0 };
handleMouseMove = (event) => {
this.setState({
x: event.clientX,
y: event.clientY
});
}
render() {
return (
<div style={{ height: '100%' }} onMouseMove={this.handleMouseMove}>
{this.props.render(this.state)}
</div>
);
}
}
function App() {
return (
<div style={{ height: '100%' }}>
<Mouse render={({ x, y }) => (
// render prop 给了我们所需要的 state 来渲染我们想要的
<h1>The mouse position is ({x}, {y})</h1>
)}/>
</div>
);
}
ReactDOM.render(<App/>, document.getElementById('root'));
复制代码
Hooks
Hooks API and by a combination of built-React Context, from the previous example can be seen by Hook state between the component sharing allows clearer and simpler.
React Hooks design
Fundamental
function FunctionalComponent () {
const [state1, setState1] = useState(1);
const [state2, setState2] = useState(2);
const [state3, setState3] = useState(3);
}
复制代码
{
memoizedState: 'foo',
next: {
memoizedState: 'bar',
next: {
memoizedState: 'bar',
next: null
}
}
}
复制代码
Functional implement in the end
capture props
Function component is inherently support props, there is no much difference on the basic usage and class components. Note that the difference between the two:
- class mount assembly props this context, the functional assembly by parameter passing;
- Due to differences in position mount, class components if this changes, then this.props will change; but always in the function components in props are immutable, and therefore comply with the principle of capture value (ie acquisition value is always at a certain time), Hooks also follow this principle.
Through an example to understand how the capture value, we can evade capture value through useRef, because useRef is variable.
state
class components | Function Component | |
---|---|---|
Creating state | this.state = {} | useState, useReducer |
Modify status | this.setState() | set function |
Update mechanism | Asynchronous update, merge several revisions to the state, to produce a copy of the | Updated simultaneously, directly modifying the target state |
State Management | A plurality of centralized management state status | A plurality of state, the state can be combined (manually) by useReducer |
performance | high | If useState initialization state need to get through a very complex calculations, please use declarative function, otherwise render repeats itself every time |
The life cycle
- componentDidMount / componentDidUpdate / componentWillUnMount
useEffect is called every time the rendering will be, a little bit can be used as packaging these life cycle;
- shouldComponentUpdate
Normally we optimize component performance, purely by way of priority to reduce the number of components render the individual components.
class Button extends React.PureComponent {}
复制代码
React Hooks useMemo may be employed in place, it can be achieved only when certain data re-render component changes, equivalent to the shouldComponentUpdate shallowEqual comes.
Forced rendering forceUpdate
As the default, each time modifying condition will cause the re-rendered, as may be set by forceUpdate a function not in use.
const forceUpdate = () => useState(0)[1];
复制代码
The principle
Based Hooks, Hooks enhanced
To a combination of boxing it!
Since the concept of each Hooks API functions are pure, more concerned about the input (input) and output (output) use, so you can function better by assembling a way, Hooks API on the basis of different characteristics are combined to create a new own Hooks characteristics.
- useState maintenance component state
- useEffect treatment side effects
- useContext listening updated change provider
useDidMount
import { useEffect } from 'react';
const useDidMount = fn => useEffect(() => fn && fn(), []);
export default useDidMount;
复制代码
useDidUpdate
import { useEffect, useRef } from 'react';
const useDidUpdate = (fn, conditions) => {
const didMoutRef = useRef(false);
useEffect(() => {
if (!didMoutRef.current) {
didMoutRef.current = true;
return;
}
// Cleanup effects when fn returns a function
return fn && fn();
}, conditions);
};
export default useDidUpdate
复制代码
useWillUnmount
When talking about useEffect already mentioned, which allows a cleanup function to return, the assembly will perform cleanup function when unmounted, and therefore can easily useWillUnmount ~
import { useEffect } from 'react';
const useWillUnmount = fn => useEffect(() => () => fn && fn(), []);
export default useWillUnmount;
复制代码
useHover
// lib/onHover.js
import { useState } from 'react';
const useHover = () => {
const [hovered, set] = useState(false);
return {
hovered,
bind: {
onMouseEnter: () => set(true),
onMouseLeave: () => set(false),
},
};
};
export default useHover;
复制代码
import { useHover } from './lib/onHover.js';
function Hover() {
const { hovered, bind } = useHover();
return (
<div>
<div {...bind}>
hovered:
{String(hovered)}
</div>
</div>
);
}
复制代码
useField
// lib/useField.js
import { useState } from 'react';
const useField = (initial) => {
const [value, set] = useState(initial);
return {
value,
set,
reset: () => set(initial),
bind: {
value,
onChange: e => set(e.target.value),
},
};
}
export default useField;
复制代码
import { useField } from 'lib/useField';
function Input {
const { value, bind } = useField('Type Here...');
return (
<div>
input text:
{value}
<input type="text" {...bind} />
</div>
);
}
function Select() {
const { value, bind } = useField('apple')
return (
<div>
selected:
{value}
<select {...bind}>
<option value="apple">apple</option>
<option value="orange">orange</option>
</select>
</div>
);
}
复制代码
Precautions
- Hook scope of use: React the functional components, the custom function Hook Lane;
- Hook function must be written in the outermost layer, which will change every time useState subscript (cursor), React to update the status in accordance with the order;
- Although each rendering will be executed Hook API, but the state (state) is always generated by a constant (within the scope of the function);
Epilogue
React Hooks offer provides new possibilities for state management, although we may require additional to maintain some internal state, but the state administration to deal with problems can be avoided by renderProps / HOC other complex ways. Hooks brings benefits as follows:
- More fine-grained code reuse, and without excessive side effects
- Functional programming style, code more concise, while reducing the use and understanding threshold
- Abatement assembly nesting
- Component data flow more clearly
In fact, custom tailored Hooks under various scenarios, to make our application more convenient and simple, hierarchy of components can ensure the integrity, there is such a pleasant functional programming style, Hooks in React 16.8 .0 version has been officially released a stable version, now began to get up! ! !