React Hook

Hook 是能讓你在函數組件中“鉤入” React 特性的函數(hook是react16.8的新增特性,讓函數組件可以使用state以及其他react特性)

一、useState

useState用來創建state變量

const [state,setState]=React.useState(0)
const [state,setState]=React.useState({name:'frank',age:'18})
// 0或{name:'frank'}為state的初始值,setState函數可以改變state的值
setState(2)
setState({...state,name:'newName'})
// 由于react更新是重新生成一個新對象,react只會生成傳入的對象,所以如果不想另一個屬性遺失就必須使用將原本的對象展開放上去

二、useReducer

useReducer是useState的綜合版
useReducer接受兩個參數,一個操作函數,一個初始值

const [state,dispatch]=React.useReducer(fn,obj)
// 調用
dispatch({type:'name'}) //參數傳給fn的action

函數

const fn =(state,action)=>{
// state為原始state;action為傳過來的參數
return 新state(obj)的值
}

初始值

const obj={
  name:'frank',
  age:'18'
}

三、useContext

useContext上下文,上下文是局部(context.provider包裹)的全局變量

// 創建上下文
const Context = React.createContext(null)
// 使用context.provider圈定作用域
<Context.Provider value={{ n, setN }}>
   app
   <Father />
</Context.Provider>
// 使用context傳過來的值
const Father = () => {
  const { n, setN } = useContext(Context) // 使用上下文的值
  const onButton = () => {
    setN(n + 1)
  }
  return (
    <div>
      father:{n}
     <button onClick={onButton}>+1</button>
    </div>
  )
}

注意:這個地方更改n的值界面也隨之更改,并不是因為react的響應式,而是因為每次調用setN都會重新渲染App,發現n的值變了界面才變

四、useEffect

useEffect 使用副作用,名字取得不是很好理解,平替的名字可以是afterRender(渲染之后執行),

// 以下三個都會在第一次渲染執行一次
useEffect(() => {}) //任何元素變化都執行
useEffect(() => {},[n]) //n變化執行
useEffect(() => {},[])  //掛載執行
useEffect(() => {
    return ()=>{}  //消亡執行
},[]) 

通常情況下useEffect都是由上往下執行,但是useLayoutEffect在它之前執行

useLayoutEffect

useLayoutEffect是在Dom創建之后,渲染之前執行。原理如下:


useLayoutEffect.png

五、memo、useMemo、和useCallback

這三個api都是為了防多次渲染而來的
舉個栗子,以下代碼中m的值沒有變,但是Child還是執行了。。怎么防止這種情況呢?

const App = () => {
  const [n, setN] = useState(0)
  const [m, setM] = useState('a')
  return (
    <div>
      <div>grandfather</div>
      <button onClick={() => { setN(i => i + 1) }}>+1</button>
      <Father n={n} />
      <Child m={m} />
    </div>
  )
}

const Father = (props) => {
  console.log('father執行了')
  return (
    <div>father:{props.n}</div>
  )
}

const Child = (props) => {
    console.log('child執行了')
    return (
        <div>child:{props.m}</div>
    )
  }
  • 將組件傳給React.memo
const Child2 = React.memo(Child) //將Child2代替Child使用
// 或 
const Child = memo(
() => {
    return (
        <div>child:{props.m}</div>
    )
  }
)

只是這么做有一個bug,那就是當props傳遞的是函數時,這個方法不生效。這時就要用到useMemo了

// 假如以下是傳遞的函數
const fn=React.useMemo(()=>{return ()=>{}},[m]) //當n變化時被傳的組件才會執行

只是這么寫是不是看著有點怪怪的。于是react提供了個語法糖,可以直接傳個函數React.useCallback(fn,value)

const fn1 = React.useCallback(()=>{},[m])

其實這就有點類似于vue的computed了,有緩存當依賴的值變化才執行

六、useRef

useRef聲明一個不變的值(這里說的不變是指內存地址不變)

// 聲明
const count = useRef(0)
// 使用
count.current += 1

因為更改useRef的值不會導致app渲染,會造成結果變了UI沒更新。解決:

const [n, setn] = useState(0)
// 調用一下
setn()

使用useState的特性重新(手動)render一下App

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容