Hook 是 React 16.8 的新增特性。它可以让你在不编写 class 的情况下使用 state 以及其他的 React 特性。
类组件的不足:
- 状态逻辑复用难
- 缺少复用机制
- 渲染属性和高阶组件导致层级冗余
- 趋向复杂难以维护
- 生命周期函数混杂不相干逻辑
- 相干逻辑分散在不同生命周期
- this指向困扰
- 内联函数过度创建新句柄
- 类成员函数不能保证this
Hook优化类组件的三个不足
- 自定义Hook方便复用状态逻辑
- 副作用的关注点分离
- 函数组件无this问题
例子对比:
普通class组件
class Foo extends React.Component {
state = {
size:[window.innerWidth,window.innerHeight]
};
onResize = ()=>{
this.setState({
size:[window.innerWidth,window.innerHeight]
});
}
componentDidMount(){
window.addEventListener("resize",this.onResize);
document.title=this.state.size.join("x");
}
componentWillUnmount(){
window.removeEventListener("resize",this.onResize);
}
render() {
const [width,height] = this.state.size;
return (
<div>
{width} x {height}
</div>
);
}
}
ReactDOM.render(
<Foo />,
document.getElementById('root')
);
渲染属性:
class Resizable extends React.Component {
state = {
size:[window.innerWidth,window.innerHeight]
};
onResize = ()=>{
this.setState({
size:[window.innerWidth,window.innerHeight]
});
}
componentDidMount(){
window.addEventListener("resize",this.onResize);
}
componentWillUnmount(){
window.removeEventListener("resize",this.onResize);
}
render() {
return this.props.render(this.state.size);
}
}
class Foo extends React.Component{
render(){
const [width,height] = this.props.size;
return (
<div>
{width} x {height}
</div>
);
}
}
ReactDOM.render(
<Resizable render={size => <Foo size={size} />} />,
document.getElementById('root')
);
高阶组件:
function resizable(Child) {
return class Wrapper extends React.Component{
state = {
size:[window.innerWidth,window.innerHeight]
};
onResize = ()=>{
this.setState({
size:[window.innerWidth,window.innerHeight]
});
}
componentDidMount(){
window.addEventListener("resize",this.onResize);
}
componentWillUnmount(){
window.removeEventListener("resize",this.onResize);
}
render() {
return <Child size={this.state.size}/>;
}
}
}
class Foo extends React.Component{
render(){
const [width,height] = this.props.size;
return (
<div>
{width} x {height}
</div>
);
}
}
const WrapperedFoo = resizable(Foo); // 包装类
ReactDOM.render(
<WrapperedFoo />,
document.getElementById('root')
);
Hook方式
import React, { useState,useEffect } from "react";
export default function Foo(){
const [size, setSize] = useState( [window.innerWidth,window.innerHeight] );
onResize = ()=>{
setSize([window.innerWidth,window.innerHeight]);
};
useEffect(() => {
window.addEventListener("resize",this.onResize);
document.title=size.join("x");
return ()=>window.removeEventListener("resize",this.onResize);
});
const [width,height] = size;
return (
<div>
{width} x {height}
</div>
);
}