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是什麼?的詳細內容。更多資訊請關注PHP中文網其他相關文章!