React hooks是React16.8的新特性,可以讓React函陣列件具有狀態,並提供類似componentDidMount和componentDidUpdate等生命週期方法。
我們大部分 React 類元件可以儲存狀態,而函陣列件不能? 並且類元件具有生命週期,而函陣列件卻不能?
React 早期版本,類元件可以通過繼承PureComponent來優化一些不必要的渲染,相對於函陣列件,React 官網沒有提供對應的方法來快取函陣列件以減少一些不必要的渲染,直接 16.6 出來的 React.memo函數。
React 16.8 新出來的Hooks可以讓React 函陣列件具有狀態,並提供類似 componentDidMount和componentDidUpdate等生命週期方法。
Hook 這個單詞的意思是"勾點"。
React Hooks 的意思是,元件儘量寫成純函數,如果需要外部功能和副作用,就用勾點把外部程式碼"鉤"進來。 React Hooks 就是那些勾點。
你需要什麼功能,就使用什麼勾點。React 預設提供了一些常用勾點,你也可以封裝自己的勾點。
所有的勾點都是為函數引入外部功能,所以 React 約定,勾點一律使用use字首命名,便於識別。你要使用 xxx 功能,勾點就命名為 usexxx。
下面介紹 React 預設提供的四個最常用的勾點。
useState()
useContext()
useReducer()
useEffect()
useState():狀態勾點
useState()用於為函陣列件引入狀態(state)。純函數不能有狀態,所以把狀態放在勾點裡面。
本文前面那個元件類,使用者點選按鈕,會導致按鈕的文字改變,文字取決於使用者是否點選,這就是狀態。使用useState()重寫如下。
import React, { useState } from "react"; export default function Button() { const [buttonText, setButtonText] = useState("Click me, please"); function handleClick() { return setButtonText("Thanks, been clicked!"); } return <button onClick={handleClick}>{buttonText}</button>; }
demo地址:https://codesandbox.io/s/nifty-waterfall-4i2dq
上面程式碼中,Button 元件是一個函數,內部使用useState()勾點引入狀態。
useState()這個函數接受狀態的初始值,作為引數,上例的初始值為按鈕的文字。該函數返回一個陣列,陣列的第一個成員是一個變數(上例是buttonText),指向狀態的當前值。第二個成員是一個函數,用來更新狀態,約定是set字首加上狀態的變數名(上例是setButtonText)。
useContext():共用狀態勾點
如果需要在元件之間共用狀態,可以使用useContext()。
現在有兩個元件 Navbar 和 Messages,我們希望它們之間共用狀態。
<div className="App"> <Navbar/> <Messages/> </div>
第一步就是使用 React Context API,在元件外部建立一個 Context。
const AppContext = React.createContext({});
元件封裝程式碼如下。
<AppContext.Provider value={{ username: 'superawesome' }}> <div className="App"> <Navbar/> <Messages/> </div> </AppContext.Provider>
上面程式碼中,AppContext.Provider提供了一個 Context 物件,這個物件可以被子元件共用。
Navbar 元件的程式碼如下。
const Navbar = () => { const { username } = useContext(AppContext); return ( <div className="navbar"> <p>AwesomeSite</p> <p>{username}</p> </div> ); }
上面程式碼中,useContext()勾點函數用來引入 Context 物件,從中獲取username屬性。
Message 元件的程式碼也類似。
const Messages = () => { const { username } = useContext(AppContext) return ( <div className="messages"> <h1>Messages</h1> <p>1 message for {username}</p> <p className="message">useContext is awesome!</p> </div> ) }
demo:https://codesandbox.io/s/react-usecontext-redux-0bj1v
useReducer():action 勾點
React 本身不提供狀態管理功能,通常需要使用外部庫。這方面最常用的庫是 Redux。
Redux 的核心概念是,元件發出 action 與狀態管理器通訊。狀態管理器收到 action 以後,使用 Reducer 函數算出新的狀態,Reducer 函數的形式是(state, action) => newState。
useReducers()勾點用來引入 Reducer 功能。
const [state, dispatch] = useReducer(reducer, initialState);
上面是useReducer()的基本用法,它接受 Reducer 函數和狀態的初始值作為引數,返回一個陣列。陣列的第一個成員是狀態的當前值,第二個成員是傳送 action 的dispatch函數。
下面是一個計數器的例子。用於計算狀態的 Reducer 函數如下。
const myReducer = (state, action) => { switch(action.type) { case('countUp'): return { ...state, count: state.count + 1 } default: return state; } }
元件程式碼如下。
function App() { const [state, dispatch] = useReducer(myReducer, { count: 0 }); return ( <div className="App"> <button onClick={() => dispatch({ type: 'countUp' })}> +1 </button> <p>Count: {state.count}</p> </div> ); }
demo:https://codesandbox.io/s/react-usereducer-redux-xqlet
由於 Hooks 可以提供共用狀態和 Reducer 函數,所以它在這些方面可以取代 Redux。但是,它沒法提供中介軟體(middleware)和時間旅行(time travel),如果你需要這兩個功能,還是要用 Redux。
useEffect():副作用勾點
useEffect()用來引入具有副作用的操作,最常見的就是向伺服器請求資料。以前,放在componentDidMount裡面的程式碼,現在可以放在useEffect()。
useEffect()的用法如下。
useEffect(() => { // Async Action }, [dependencies])
上面用法中,useEffect()接受兩個引數。第一個引數是一個函數,非同步操作的程式碼放在裡面。第二個引數是一個陣列,用於給出 Effect 的依賴項,只要這個陣列發生變化,useEffect()就會執行。第二個引數可以省略,這時每次元件渲染時,就會執行useEffect()。
下面看一個例子。
const Person = ({ personId }) => { const [loading, setLoading] = useState(true); const [person, setPerson] = useState({}); useEffect(() => { setLoading(true); fetch(`https://swapi.co/api/people/${personId}/`) .then(response => response.json()) .then(data => { setPerson(data); setLoading(false); }); }, [personId]) if (loading === true) { return <p>Loading ...</p> } return <div> <p>You're viewing: {person.name}</p> <p>Height: {person.height}</p> <p>Mass: {person.mass}</p> </div> }
上面程式碼中,每當元件引數personId發生變化,useEffect()就會執行。元件第一次渲染時,useEffect()也會執行。
demo:https://codesandbox.io/s/react-useeffect-redux-9t3bg
建立自己的 Hooks
上例的 Hooks 程式碼還可以封裝起來,變成一個自定義的 Hook,便於共用。
const usePerson = (personId) => { const [loading, setLoading] = useState(true); const [person, setPerson] = useState({}); useEffect(() => { setLoading(true); fetch(`https://swapi.co/api/people/${personId}/`) .then(response => response.json()) .then(data => { setPerson(data); setLoading(false); }); }, [personId]); return [loading, person]; };
上面程式碼中,usePerson()就是一個自定義的 Hook。
Person 元件就改用這個新的勾點,引入封裝的邏輯。
const Person = ({ personId }) => { const [loading, person] = usePerson(personId); if (loading === true) { return <p>Loading ...</p>; } return ( <div> <p>You're viewing: {person.name}</p> <p>Height: {person.height}</p> <p>Mass: {person.mass}</p> </div> ); };
demo:https://codesandbox.io/s/react-useeffect-redux-ghl7c
更多程式設計相關知識,請存取:!!
以上就是react hooks是什麼?的詳細內容,更多請關注TW511.COM其它相關文章!