react-hook完全上手指南

本文深入探讨了React Hooks的出现背景,详细解释了Class Component存在的问题,如this指向、编译大小以及生命周期管理。随着Function Component+Hooks的结合,这些问题得到了有效解决。文章通过示例介绍了useState、useEffect、useContext、useReducer等核心Hooks的用法和原理,并讨论了自定义Hooks和常见问题,展示了Hooks如何弥补Function Component的不足,推动React组件设计的发展。
摘要由CSDN通过智能技术生成

1 Why Hook?
1.1 从React组件设计理论说起
React以一种全新的编程范式定义了前端开发约束,它为视图开发带来了一种全新的心智模型:

React认为,UI视图是数据的一种视觉映射,即UI = F(DATA),这里的F需要负责对输入数据进行加工、并对数据的变更做出响应
公式里的F在React里抽象成组件,React是以组件(Component-Based)为粒度编排应用的,组件是代码复用的最小单元
在设计上,React采用props属性来接收外部的数据,使用state属性来管理组件自身产生的数据(状态),而为了实现(运行时)对数据变更做出响应需要,React采用基于类(Class)的组件设计!
除此之外,React认为组件是有生命周期的,因此开创性地将生命周期的概念引入到了组件设计,从组件的create到destory提供了一系列的API供开发者使用
这就是React组件设计的理论基础,我们最熟悉的React组件一般长这样:

// React基于Class设计组件
class MyConponent extends React.Component {
// 组件自身产生的数据
state = {
counts: 0
}

// 响应数据变更
clickHandle = () => {
this.setState({ counts: this.state.counts++ });
if (this.props.onClick) this.props.onClick();
}

// lifecycle API
componentWillUnmount() {
console.log(‘Will mouned!’);
}

// lifecycle API

componentDidMount() {
console.log(‘Did mouned!’);
}

// 接收外来数据(或加工处理),并编排数据在视觉上的呈现
render(props) {
return (
<>

Input content: {props.content}, btn click counts: {this.state.counts}

Add
</>
);
}
}
1.2 Class Component的问题
1.2.1 组件复用困局
组件并不是单纯的信息孤岛,组件之间是可能会产生联系的,一方面是数据的共享,另一个是功能的复用:

对于组件之间的数据共享问题,React官方采用单向数据流(Flux)来解决
对于(有状态)组件的复用,React团队给出过许多的方案,早期使用CreateClass + Mixins,在使用Class Component取代CreateClass之后又设计了Render Props和Higher Order Component,直到再后来的Function Component+ Hooks设计,React团队对于组件复用的探索一直没有停止
HOC使用(老生常谈)的问题:

嵌套地狱,每一次HOC调用都会产生一个组件实例
可以使用类装饰器缓解组件嵌套带来的可维护性问题,但装饰器本质上还是HOC
包裹太多层级之后,可能会带来props属性的覆盖问题
Render Props:

数据流向更直观了,子孙组件可以很明确地看到数据来源
但本质上Render Props是基于闭包实现的,大量地用于组件的复用将不可避免地引入了callback hell问题
丢失了组件的上下文,因此没有this.props属性,不能像HOC那样访问this.props.children
1.2.2 Javascript Class的缺陷
1、this的指向(语言缺陷)

class People extends Component {
state = {
name: ‘dm’,
age: 18,
}

handleClick(e) {
// 报错!
console.log(this.state);
}

render() {
const { name, age } = this.state;
return (

My name is {name}, i am {age} years old.
);
}
}
createClass不需要处理this的指向,到了Class Component稍微不慎就会出现因this的指向报错。

2、编译size(还有性能)问题:

// Class Component
class App extends Component {
state = {
count: 0
}

componentDidMount() {
console.log(‘Did mount!’);
}

increaseCount = () => {
this.setState({ count: this.state.count + 1 });
}

decreaseCount = () => {
this.setState({ count: this.state.count - 1 });
}

render() {
return (
<>

Counter


Current count: {this.state.count}


Increase
Decrease


</>
);
}
}

// Function Component
function App() {
const [ count, setCount ] = useState(0);
const increaseCount = () => setCount(count + 1);
const decreaseCount = () => setCount(count - 1);

useEffect(() => {
console.log(‘Did mount!’);
}, []);

return (
<>

Counter


Current count: {count}


Increase
Decrease


</>
);
}
Class Component编译结果(Webpack):

var App_App = function (_Component) {
Object(inherits[“a”])(App, _Component);

function App() {
var _getPrototypeOf2;
var _this;
Object(classCallCheck[“a”])(this, App);
for (var _len = arguments.length, args = new Array(_len), _key = 0; _key < _len; _key++) {
args[_key] = arguments[_key];
}
_this = Object(possibleConstructorReturn[“a”])(this, (_getPrototypeOf2 = Object(getPrototypeOf[“a”])(App)).call.apply(_getPrototypeOf2, [this].concat(args)));
_this.state = {
count: 0
};
_this.increaseCount = function () {
_this.setState({
count: _this.state.count + 1
});
};
_this.decreaseCount = function () {
_this.setState({
count: _this.state.count - 1
});
};
return _this;
}
Object(createClass[“a”])(App, [{
key: “componentDidMount”,
value: function componentDidMount() {
console.log(‘Did mount!’);
}
}, {
key: “render”,
value: function render() {
return react_default.a.createElement(//);
}
}]);
return App;
}(react[“Component”]);
Function Component编译结果(Webpack):

function App() {
var _useState = Object(react[“useState”])(0),
_useState2 = Object(slicedToArray[“a” /* default */ ])(_useState, 2),
count = _useState2[0],
setCount = _useState2[1];
var increaseCount = function increaseCount() {
return setCount(count + 1);
};
var decreaseCount = function decreaseCount() {
return setCount(count - 1);
};
Object(react[“useEffect”])(function () {
console.log(‘Did mount!’);
}, []);
return react_default.a.createElement();
}
Javascript实现的类本身比较鸡肋,没有类似

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值