若是你以为能够,请多点赞,鼓励我写出更精彩的文章🙏。若是你感受有问题,也欢迎在评论区评论,三人行,必有我师焉javascript
若是是你一个React
开发者,或多或少接触了React 16.8
的一些新特性。例如:React.memo()
、React.lazy
、React.Suspense
等一些比较好的新特性。可是,其中我认为,最爽的是React-Hooks
的提出。html
这意味着啥,React
项目组,对性能要求更加严格(Hooks
推崇的是函数组件
,在渲染速度上是比类组件
快很多)。无论你是不是一个React
开发的老鸟,可是在实际项目开发中,确定见过让人头疼的代码堆砌。java
尤为在一些公司早期的项目代码中,组件化的思惟很匮乏,直接是按一个页面一个组件。一个生命周期的方法中嵌套着5-10个不相关的代码。原来我在某东的时候,有的组件甚至是1000行代码,就是纯粹的去堆砌一些逻辑。长此以往,就变成了一些魔鬼代码,让人望而生畏。react
而Hooks
的出现,对一些魔鬼代码的出现,有了一些制约。(其实之因此会出现魔鬼代码,仍是因为研发团队对如何进行组件划分或者是逻辑复用的认知度不够而致使的)。git
虽然,不用Hooks
,利用HOC
/Render Props
也能够实现组件化和逻辑复用。可是在实际项目开发中,发现不论是HOC
仍是Render Props
将组件进行屡次嵌套,就会陷入wrapper hell
。若是你开发中用过React-dev-tools
看页面。就会发现,一个简单的组件,被层层包裹。那场面简直是车祸现场,惨不忍睹。github
和你们墨迹了半天,算是对现有的React
的开发模式的吐槽吧。客官,不要着急离开,这就正式进入正题。编程
今天带你们来看看Hooks
中比较基础的API:useState/useEffect
。至于像其余的自定义hook,会专门有一篇文章来给你们详细讲述。json
顺便提一句,这篇文章只是一个Hooks
的简单介绍和入门。这个技术方案是针对函数组件的。想了解为何FaceBook构建了这个技术方案,或者是解决了什么技术痛点。 能够参考官网api
React Hooks
是将React.Component
的特性添加到函数组件的一种方式。数组
例如将
Hooks可以让开发者不使用
class
来使用React
的特性
可能你们会问,是否是之后React
官网就不会继续维护用class
来构建组件的方式了。这一点大可没必要担忧。
同时也有一点须要你们清楚就是:Hook
的出现只是新增了一种处理逻辑的方式,而不是让你将原有的类组件重写为函数组件。
假如咱们有以下的组件
import React, { Component } from 'react';
class JustAnotherCounter extends Component {
state = {
count: 0
};
setCount = () => {
this.setState({ count: this.state.count + 1 });
};
render() {
return (
<div>
<h1>{this.state.count}</h1>
<button onClick={this.setCount}>计算</button>
</div>
);
}
}
复制代码
useState
在函数组件中使用state
import React, { useState } from 'react';
function JustAnotherCounter() {
const [count, setCount] = useState(0);
return (
<div>
<h1>{count}</h1>
<button onClick={() => setCount(count + 1)}>计算</button>
</div>
);
}
复制代码
你可能对useState()
的语法不是很熟悉。可是发现,它是使用了数组的解构语法。这就像咱们经过对象的解构从某个对象中剥取一些特定属性同样。
让咱们经过比较对象的解构和数组的解构,来看看useState
是如何选择了数组的解构。
const users = { admin: 'chris', user: 'nick' };
// 获取admin和user而且为他们起一个别名
const { admin: SuperAdmin, user: SuperUser } = users;
复制代码
在进行对象结构的时候,若是须要对解构的属性起一个别名,就须要用额外的变量去接收。而咱们经过数组结构的话,咱们只须要定义须要接收数组值的变量便可。第一个变量就是数组中的第一个值
//
const users = ['chris', 'nick'];
// 获取值的同时为值起了别名
const [SuperAdmin, SuperUser] = users;
复制代码
useState
返回了两个变量,而且经过上文的分析,咱们能够给这两个变量随意起名字。
this.state
this.setState
在咱们调用useState
的时候,传入了一个值,这个值是做为第一个变量的初始值。
因为在实际开发中一个逻辑片断不可能细分到只有一个state
去维护和控制,因此Hooks
支持在一个函数组件中,屡次调用useState
添加多个状态值。
import React, { useState } from 'react';
function AllTheThings() {
const [count, setCount] = useState(0);
const [products, setProducts] = useState([{ name: 'Surfboard', price: 100 }]);
const [coupon, setCoupon] = useState(null);
return <div>{/此处能够随意使用已经构建的状态值/}</div>;
}
复制代码
State Hook
让咱们能够在函数组件中使用state
,让函数组件在使用上变得更加灵活。而Effect Hook
使得函数组件拥有了生命周期方法。
函数组件中的Effects其实等同于类组件的
componentDidMount
、componentDidUpdate
和componentWillUnmount
的结合体
字如其名,Effect
就是维护一些具备反作用的操做
Effects
在每次render
以后触发,无论组件是不是首次渲染
import React, { Component } from 'react';
class DoSomethingCrazy extends Component {
componentDidMount() {
console.log('我要起飞了!');
document.title = '这是标题';
}
render() {
return <div>作点疯狂的事</div>;
}
}
复制代码
useEffect
修改组件function DoSomethingCrazy() {
useEffect(() => {
console.log('我要起飞了');
document.title = '这是标题';
});
return <div>作点疯狂的事</div>;
}
复制代码
经过比较,是否是感受利用useEffect
在代码量上还有逻辑捆绑上比传统的组件都具备很大的优点。
因为useEffect()
在每次render
的以后,总会被调用。那咱们是否有一个方式,只限制它在首次加载时调用。
其实Effect Hook接收第二个参数(Array类型)。只有数组中的值发生变化了,才会调用useEffect()
而不是每次在渲染的时候调用。
// 当第二个参数为空数组([])的时候,只是被调用一次(也就至关于类组件中componentDidMount)
useEffect(() => {
// 值运行一次
}, []);
复制代码
// 只有count变化才运行
useEffect(
() => {
//只有count变化才运行
},
[count]
);
复制代码
咱们上文说过,函数组件中的Effects其实等同于类组件的componentDidMount
、componentDidUpdate
和componentWillUnmount
的结合体。而经过控制第二个参数的值,能够模拟componentDidMount
、componentDidUpdate
。可是componentWillUnmount
如何才会调用呢。
咱们只须要在useEffect()
中返回一个函数,既能够模拟componentWillUnmount
的功能,也就是在组件unmounts时调用。
useEffect(() => {
UsersAPI.subscribeToUserLikes();
// unsubscribe
return () => {
UsersAPI.unsubscribeFromUserLikes();
};
});
复制代码
既然在函数组件中能够单独使用useState
来模拟类组件的this.state
的功能,用useEffect
来模拟类组件的生命周期。那咱们能够同时利用useState
和useEffect
将函数组件变成有状态组件。
咱们经过一个真实的例子来说解一下如何共同使用这些API。咱们经过useEffect()
来获取GitHub API
而且用useState()
来存储。
useState
import React, { useState } from 'react';
function GitHubUsers() {
const [users, setUsers] = useState([]);
}
复制代码
咱们经过useState([])
的参数将users
的值,赋为[]
。
useEffect
来获取数据import React, { useState } from 'react';
function GitHubUsers() {
const [users, setUsers] = useState([]);
useEffect(() => {
fetch('https://api.github.com/users')
.then(response => response.json())
.then(data => {
setUsers(data); // 为users赋值
});
}, []); //经过useEffect的第二个参数,来约定,该操做只被调用一次
}
复制代码
import React, { useState, useEffect } from 'react';
import ReactDOM from 'react-dom';
function GitHubUsers() {
// 刚才的代码
return (
<div className="section">
{users.map(user => (
<div key={user.id} className="card">
<h5>{user.login}</h5>
</div>
))}
</div>
);
}
复制代码
这样一个简单的Hooks
的例子就完成了。
上面的分析步骤,只是简单介绍了useState
/useEffect
的使用方式,我相信你们在使用过程当中,确定遇到了比这还复杂的。可是,万变不离其宗。都是利用hook
的一些API。为函数组件赋予状态。
还有一点,由于在使用useState
或者useEffect
的时候,咱们能够将相关的代码进行统一处理,这样无论在业务开发仍是代码维护上,变的很清楚。而不是像原来的开发同样,一个生命周期包含着无数的不相干的逻辑代码。
而且,hooks
还支持自定义。本人认为,这才是hooks
的真正强大之处。经过自定义一些业务代码,真正的实现逻辑复用。能够有效的减小wrapper hell
。让代码实现切片化编程。