若是你以爲能夠,請多點贊,鼓勵我寫出更精彩的文章🙏。若是你感受有問題,也歡迎在評論區評論,三人行,必有我師焉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
。讓代碼實現切片化編程。