成人怡红院-成人怡红院视频在线观看-成人影视大全-成人影院203nnxyz-美女毛片在线看-美女免费黄

站長資訊網
最全最豐富的資訊網站

react hook和class的區別有哪些

區別:1、hooks的寫法比class簡潔;2、hooks的業務代碼比class更加聚合;3、class組件的邏輯復用通常用render props以及HOC兩種方式,而react hooks提供了自定義hooks來復用邏輯。

react hook和class的區別有哪些

本教程操作環境:Windows7系統、react17.0.1版、Dell G3電腦。

react hooks與class組件有哪些區別?下面就來帶大家對比一下react hooks和class組件,聊聊它們的區別。

react-hooks解決的問題

  • 函數組件中不能擁有自己的狀態(state)。在hooks之前函數組件是無狀態的,都是通過props來獲取父組件的狀態,但是hooks提供了useState來維護函數組件內部的狀態。

  • 函數組件中不能監聽組件的生命周期。useEffect聚合了多個生命周期函數。

  • class組件中生命周期較為復雜(在15版本到16版本的變化大)。

  • class組件邏輯難以復用(HOC,render props)。

hooks對比class的好處(對比)

1、寫法更加的簡潔

我們以最簡單的計數器為例:

class組件

class ExampleOfClass extends Component {   constructor(props) {     super(props)     this.state = {       count: 1     }   }   handleClick = () => {     let { count } = this.state     this.setState({       count: count+1     })   }   render() {     const { count } = this.state     return (       <div>         <p>you click { count }</p>         <button onClick={this.handleClick}>點擊</button>       </div>     )   } }

hooks

function ExampleOfHooks() {     const [count, setCount] = useState(0)     const handleClick = () => {         setCount(count + 1)     }     return (       <div>         <p>you click { count }</p>         <button onClick={handleClick}>點擊</button>       </div>     ) }

可以看到使用hooks的代碼相比class組件代碼更加的簡潔、清晰。

2、業務代碼更加聚合

使用class組件經常會出現一個功能出現在兩個生命周期函數內的情況,這樣分開寫有時候可能會忘記。比如:

let timer = null componentDidMount() {     timer = setInterval(() => {         // ...     }, 1000) } // ... componentWillUnmount() {     if (timer) clearInterval(timer) }

由于添加定時器和清除定時器是在兩個不同的生命周期函數,中間可能會有很多其他的業務代碼,所以可能會忘記清除定時器,如果在組件卸載時沒有添加清楚定時器的函數就可能會造成內存泄漏、網絡一直請求等問題。

但是使用hooks可以讓代碼更加的集中,方便我們管理,也不容易忘記:

useEffect(() => {     let timer = setInterval(() => {         // ...     }, 1000)     return () => {         if (timer) clearInterval(timer)     } }, [//...])

3、邏輯復用方便

class組件的邏輯復用通常用render props以及HOC兩種方式。react hooks提供了自定義hooks來復用邏輯。

下面以獲取鼠標在頁面的位置的邏輯復用為例:

class組件render props方式復用

import React, { Component } from 'react'  class MousePosition extends Component {   constructor(props) {     super(props)     this.state = {       x: 0,       y: 0     }   }    handleMouseMove = (e) => {     const { clientX, clientY } = e     this.setState({       x: clientX,       y: clientY     })   }    componentDidMount() {     document.addEventListener('mousemove', this.handleMouseMove)   }    componentWillUnmount() {     document.removeEventListener('mousemove', this.handleMouseMove)   }    render() {     const { children } = this.props     const { x, y } = this.state     return(       <div>         {           children({x, y})         }       </div>     )   }  }  // 使用 class Index extends Component {   constructor(props) {     super(props)   }    render() {     return (       <MousePosition>         {           ({x, y}) => {             return (               <div>                 <p>x:{x}, y: {y}</p>               </div>             )           }         }       </MousePosition>     )   } }  export default Index

自定義hooks方式復用

import React, { useEffect, useState } from 'react'  function usePosition() {   const [x, setX] = useState(0)   const [y, setY] = useState(0)    const handleMouseMove = (e) => {     const { clientX, clientY } = e     setX(clientX)     setY(clientY)   }     useEffect(() => {     document.addEventListener('mousemove', handleMouseMove)     return () => {       document.removeEventListener('mousemove', handleMouseMove)     }   })   return [     {x, y}   ] }  // 使用 function Index() {   const [position] = usePosition()   return(     <div>       <p>x:{position.x},y:{position.y}</p>     </div>   ) }  export default Index

可以很明顯的看出使用hooks對邏輯復用更加的方便,使用的時候邏輯也更加清晰。

hooks常見的一些API使用

1、useState

語法

const [value, setValue] = useState(0)

這種語法方式是ES6的數組結構,數組的第一個值是聲明的狀態,第二個值是狀態的改變函數。

每一幀都有獨立的狀態

個人理解針對每一幀獨立的狀態是采用了閉包的方法來實現的。

function Example() {   const [val, setVal] = useState(0)   const timeoutFn = () => {       setTimeout(() => {         // 取得的值是點擊按鈕的狀態,不是最新的狀態           console.log(val)       }, 1000)   }   return (       <>           <p>{val}</p>           <button onClick={()=>setVal(val+1)}>+</button>           <button onClick={timeoutFn}>alertNumber</button>       </>   ) }

當組件的狀態或者props更新時,該函數組件會被重新調用渲染,并且每一次的渲染都是獨立的都有自己獨立的props以及state,不會影響其他的渲染。

2、useEffect

語法

useEffect(() => {     //handler function...          return () => {         // clean side effect     } }, [//dep...])

useEffect接收一個回調函數以及依賴項,當依賴項發生變化時才會執行里面的回調函數。useEffect類似于class組件didMount、didUpdate、willUnmount的生命周期函數。

注意點

  • useEffect是異步的在組件渲染完成后才會執行

  • useEffect的回調函數只能返回一個清除副作用的處理函數或者不返回

  • 如果useEffect傳入的依賴項是空數組那么useEffect內部的函數只會執行一次

3、useMemo、useCallback

useMemo和useCallback主要用于減少組件的更新次數、優化組件性能的。

  • useMemo接收一個回調函數以及依賴項,只有依賴項變化時才會重新執行回調函數。

  • useCallback接收一個回調函數以及依賴項,并且返回該回調函數的memorize版本,只有在依賴項重新變化時才會重新新的memorize版本。

語法

const memoDate = useMemo(() => data, [//dep...]) const memoCb = useCallback(() => {//...}, [//dep...])

在優化組件性能時針對class組件我們一般使用React.PureComponent,PureComponent會在shouldUpdate進行一次錢比較,判斷是否需要更新;針對函數組件我們一般使用React.memo。但是在使用react hooks時由于每一次渲染更新都是獨立的(生成了新的狀態),即使使用了React.memo,也還是會重新渲染。

比如下面這種場景,改變子組件的name值后由于父組件更新后每次都會生成新值(addAge函數會改變),所以子組件也會重新渲染。

function Parent() {   const [name, setName] = useState('cc')   const [age, setAge] = useState(22)    const addAge = () => {     setAge(age + 1)   }    return (     <>       <p>父組件</p>       <input value={name} onChange={(e) => setName(e.target.value)} />       <p>age: {age}</p>       <p>-------------------------</p>       <Child addAge={addAge} />     </>   ) }  const Child = memo((props) => {   const { addAge } = props   console.log('child component update')   return (     <>       <p>子組件</p>       <button onClick={addAge}>click</button>     </>   ) })

使用useCallback優化

function Parent() {   const [name, setName] = useState('cc')   const [age, setAge] = useState(22)    const addAge = useCallback(() => {     setAge(age + 1)   }, [age])    return (     <>       <p>父組件</p>       <input value={name} onChange={(e) => setName(e.target.value)} />       <p>age: {age}</p>       <p>-------------------------</p>       <Child addAge={addAge} />     </>   ) }  const Child = memo((props) => {   const { addAge } = props   console.log('child component update')   return (     <>       <p>子組件</p>       <button onClick={addAge}>click</button>     </>   ) })

只有useCallback的依賴性發生變化時,才會重新生成memorize函數。所以當改變name的狀態是addAge不會變化。

4、useRef

useRef類似于react.createRef。

const node = useRef(initRef)

useRef 返回一個可變的 ref 對象,其 current 屬性被初始化為傳入的參數(initRef)

作用在DOM上

const node = useRef(null) <input ref={node} />

這樣可以通過node.current屬性訪問到該DOM元素。

需要注意的是useRef創建的對象在組件的整個生命周期內保持不變,也就是說每次重新渲染函數組件時,返回的ref 對象都是同一個(使用 React.createRef ,每次重新渲染組件都會重新創建 ref)。

5、useReducer

useReducer類似于redux中的reducer。

語法

const [state, dispatch] = useReducer(reducer, initstate)

useReducer傳入一個計算函數和初始化state,類似于redux。通過返回的state我們可以訪問狀態,通過dispatch可以對狀態作修改。

const initstate = 0; function reducer(state, action) {   switch (action.type) {     case 'increment':       return {number: state.number + 1};     case 'decrement':       return {number: state.number - 1};     default:       throw new Error();   } } function Counter(){     const [state, dispatch] = useReducer(reducer, initstate);     return (         <>           Count: {state.number}           <button onClick={() => dispatch({type: 'increment'})}>+</button>           <button onClick={() => dispatch({type: 'decrement'})}>-</button>         </>     ) }

6、useContext

通過useContext我們可以更加方便的獲取上層組件提供的context。

父組件

import React, { createContext, Children } from 'react' import Child from './child'  export const MyContext = createContext()  export default function Parent() {    return (     <div>       <p>Parent</p>       <MyContext.Provider value={{name: 'cc', age: 21}}>         <Child />       </MyContext.Provider>     </div>   ) }

子組件

import React, { useContext } from 'react' import { MyContext } from './parent'  export default function Parent() {   const data = useContext(MyContext) // 獲取父組件提供的context   console.log(data)   return (     <div>       <p>Child</p>     </div>   ) }

使用步驟

  • 父組件創建并導出context:export const MyContext = createContext()
  • 父組件使用providervalue提供值:<MyContext.provide value={{name: 'cc', age: 22}} />
  • 子組件導入父組件的context:import { MyContext } from './parent'
  • 獲取父組件提供的值:const data = useContext(MyContext)

不過在多數情況下我們都不建議使用context,因為會增加組件的耦合性。

7、useLayoutEffect

useEffect 在全部渲染完畢后才會執行;useLayoutEffect 會在 瀏覽器 layout之后,painting之前執行,并且會柱塞DOM;可以使用它來讀取 DOM 布局并同步觸發重渲染。

export default function LayoutEffect() {   const [color, setColor] = useState('red')   useLayoutEffect(() => {       alert(color) // 會阻塞DOM的渲染   });   useEffect(() => {       alert(color) // 不會阻塞   })   return (       <>         <div id="myDiv" style={{ background: color }}>顏色</div>         <button onClick={() => setColor('red')}>紅</button>         <button onClick={() => setColor('yellow')}>黃</button>       </>   ) }

上面的例子中useLayoutEffect會在painting之前執行,useEffect在painting之后執行。

hooks讓函數組件擁有了內部狀態、生命周期,使用hooks讓代碼更加的簡介,自定義hooks方便了對邏輯的復用,并且擺脫了class組件的this問題;但是在使用hooks時會產生一些閉包問題,需要仔細使用。

贊(0)
分享到: 更多 (0)
?
網站地圖   滬ICP備18035694號-2    滬公網安備31011702889846號
亚洲熟伦熟妇AV无码专区| 婷婷丁香五月激情综合| 日韩激情在线小视频观看| 色又黄又爽18禁免费网站现观看| 无码人妻精品一区二区蜜桃AV| 亚洲AⅤ中文无码字幕色下载软件| 亚洲丁香婷婷久久一区二区| 亚洲综合精品成人| 99精品国产福利在线观看| WC女厕撒尿七Ⅴ偷拍| 顶级私人家庭影院| 国产一区二区在线视频| 久久精品人人做人人爽电影| 女强人被春药精油按摩4| 日韩人妻潮喷中文在线视频| 午夜无码无遮挡在线视频| 亚洲人成图片小说网站| AV大片在线无码永久免费网址| 成人综合婷婷国产精品久久蜜臀 | 热99RE久久免费视精品频| 天堂8在/线中文在线资源8| 亚洲成A人片无码不卡| 中文字幕AV一区中文字幕天堂 | 色噜噜狠狠色综合网| 亚洲AV永久精品无码| 中文字幕人妻丝袜成熟乱九区| 粗大黑人巨茎大战欧美成人免费看| 国产亚洲情侣一区二区无| 美丽的熟妇中文字幕| 色哟哟最新在线观看入口| 亚洲啪AV永久无码精品放毛片| WWW内射国产在线观看| 国产女人被躁到高潮的AV| 猫咪WWW免费人成网站| 深入浅出TXL金银花讲的什么| 亚洲六月丁香色婷婷综合久久| GOGO大胆啪啪艺术| 国产做床爱无遮挡免费视频| 欧美极品另类ⅤIDEOSDE| 我故意没有穿内裤坐公车让| 曰本A级毛片无卡免费视频VA| 丰满少妇奶水一区二区三区| 久久久久久久久久久精品 | 国产精品国产三级国产专I| 久久亚洲私人国产精品VA| 三级4级全黄60分钟| 亚洲色偷偷综合亚洲AVYP| 成人A级毛片免费观看| 久久精品99国产精品日本| 日韩AV无码成人精品国产| 亚洲熟妇无码久久精品疯| 粉嫩虎白女毛片人体| 老男人把舌头伸进我下面| 我的娇妻QUEEN| 8x8x熟妇一区二区三区| 国产在线精品一区二区三区不卡| 欧美性爱操逼大鸡吧| 亚洲国产成人久久精品APP| らだ天堂√在线WWW| 精品人妻一区二区三区乱码| 上课忘穿内裤被老师摸到高潮| 一女多男3根一起进去爽吗| 国产风流老太婆大BBBHD视频| 免费观看的A级毛片的网站| 性欧美ⅩXX1819内谢| となりの家のネツト在线 | 国产精品毛片无码| 欧亚精品一区三区免费| 亚洲女毛多水多21P| 国产99视频精品免费视看9| 男女无遮挡XX00动态图120秒| 亚洲AV一二三区成人影片| 东北往事之黑道风云20年第二部| 乱人伦人妻中文字幕无码| 亚洲AV乱码一区二区三区在线观看 | 亚洲VA久久久噜噜噜久久天堂| 成熟丰满熟妇偷拍XXXXX| 美女扒开奶罩露出奶头视频网站| 亚洲AV无码精品色午夜| 丰满爆乳无码一区二区三区| 欧美丰满熟妇BBBBBB性亚洲| 亚洲性啪啪无码AV天堂| 国产毛片一二区三区四区| 日本最大但人文艺术欣赏的背景| 中文字幕乱理片人妻无码888| 护士被强女千到高潮视频| 天堂中文在线最新版地址| JZZIJZZIJ日本成熟少妇| 老师抱着我在教室做| 亚洲精品国产AV成拍色拍婷婷| 国产精品嫩草影院永久…| 日产精品一线二线三线芒 | 欧美巨大XXXX做受| 永久免费AV无码国产网站 | 国产精品呻吟AV久久高潮| 日本人妻丰满熟妇久久久久久| 50岁老熟人乱一区二区三区| 久久久亚洲欧洲日产国码是AV| 亚洲国产AV一区二区三区丶| 国产精品无码不卡一区二区三区| 日韩精品人妻中文字幕有码 | 影音先锋熟女少妇AV资源| 极品少妇被猛的白浆直喷白浆 | 少妇粉嫩小泬喷水视频WWW| CHINESE勾搭VIDEOS| 免费看成人毛片无码视频| 一边摸一边叫床一边爽AV| 精品熟人妻一区二区三区在线 | 精品国产午夜福利在线观看| 性妇WBBBB搡BBBB嗓小说| 国产妇女馒头高清泬20P多毛| 少妇高潮流白浆在线观看| 成人无码视频在线观看| 国产成人精品综合久久久久性色 | ZZTT155.CCM黑料| 欧美精品双插重口在线播放 | 国产精品国产AV片国产| 少女たちよ在线观看动漫在线观看 | 护士人妻HD中文字幕| 亚洲爆乳无码专区WWW| 黑人大战欲求不满人妻| 亚洲AV无码片在线观看| 狠狠色噜噜狠狠狠狠97俺也去| 亚洲AV无码一区二区三区系列| 黑人巨大精品欧美一区二区免费| 亚洲AV无码成人黄网站在线观看 | 亚洲人成色777777精品百度| 精品国产一区二区亚洲人成毛片| 亚洲精品成人福利网站| 久久精品国产亚洲AV麻豆软件| 亚洲中文字幕在线无码一区二区| 久久人妻夜夜做天天爽| 曰本女人与公拘交酡| 男人又粗又黑又硬的东西| 55夜色66夜色国产精品视频| 欧美交换配乱吟粗大和黄| あざらしそふと官网| 日本无人区码一码二码三码四码| 大明荫蒂女人毛茸茸| 我和大佬的365天| 韩国精品久久久久久无码| 亚洲欧美日韩国产成人| 六月丁香婷婷色狠狠久久| 99RIAV国产精品视频| 人妻熟妇乱又伦精品视频APP| 丰满少妇奶水一区二区三区| 无码口爆内射颜射后入| 韩漫无遮漫画全集观看| 亚洲伊人伊成久久人综合网| 免费国产成人高清在线视频| 锕锕锕锕锕~好深啊免费软件| 少妇饥渴偷公乱第一章全文| 国产无遮挡18禁网站免费| 亚洲男人的天堂AV手机在线观看| 浪货两个都满足不了你J视频| FREEXXXXHD国语对白| 少妇激情一区二区三区视频| 国产亚洲VA综合人人澡精品| 亚洲中文无码A∨在线观看| 能在线观看的一区二区三区| 成人无码激情视频在线观看| 五十路レンタのおばさん| 精品无码日韩一区二区三区不卡| 18禁爆乳无遮挡免费观看日本动| 日本欧美大码A在线观看| 国产精品爽爽VA在线观看网站| 亚洲欧美日韩中文高清WWW| 免费网站看V片在线18禁无码| 成人爽A毛片在线视频| 亚洲AAAAA特级| 乱人伦人成品精国产在线| 被窝影院午夜无码国产| 午夜亚洲国产理论片中文飘花| 久久亚洲AV成人无码国产| 办公室撕开奶罩揉吮奶头H文 | 精品国产污污免费网站入口| 985大学排名一览表| 他的粗大把她捣出白沫| 精品无码久久久久国产| AV天堂午夜精品一区| 无码αv人妻一区二区三区| 久久AV无码AV高潮AV喷吹| ZOOFILIA杂交JAPAN| 性高朝久久久久久久| 免费无码一区二区三区蜜桃大| 丰满岳乱妇在线观看中字| 亚洲欧美日韩国产成人精品影院| 欧美人与动性XXXXBBBB| 国产乱码卡二卡三卡43| 中文字幕无码乱人伦| 太多了太满了肚子装不下了| 久久精品国产精油按摩| 成人艳情一二三区| 亚洲色在线无码国产精品不卡| 忍着娇喘在公面前被夜袭| 狠狠色噜噜狠狠狠777米奇小说| FREE性满足孕妇VⅠDE0S| 亚洲AV无码专区亚洲AV不卡| 欧洲VODAFONEWIFI喷| 教室停电了校草挺进我体内|