useState
用來聲明狀態變量。
import React, { useState } from 'react';
// ...
const [ count , setCount ] = useState(0);
// ...
- count 聲明的變量
- setCount 設用來更新變量的函數
- 0 初始值
- 多個狀態聲明不能出現在條件判斷語句中
useEffect
用來代替生命周期函數。
import React, { useEffect } from 'react';
useEffect(()=>{
// some code
})
- 第一次組件渲染和每次組件更新都會執行這個函數
- useEffect中的函數的執行不會阻礙瀏覽器更新視圖,這些函數是異步的
使用 useEffect 實現類似 componentWillUnmount
useEffect(()=>{
return () => {
// some code
}
})
- 返回一個函數實現解綁
- 但是這樣會導致每次狀態發生變化,useEffect 都進行解綁
useEffect(()=>{
return () => {
// some code
}
}, [])
使用第二個參數,制定哪些狀態發生變化時再解綁
useContext
跨越組件層級直接傳遞變量,實現狀態共享。
- useContext 解決的是組件之間值傳遞的問題
- redux 解決的是應用中統一管理狀態的問題
- useContext 通過和 useReducer 的配合使用,可以實現類似 Redux 的作用
Outer 組件
import React, { createContext } from 'react'
const ValueContext = createContext()
function Outer(){
return (
<>
<ValueContext.Provider value={'我是傳向 Inner 組件的值'}>
<Inner />
</ValueContext.Provider>
</>
)
}
export default Outer;
- 使用 createContext 創建 context
- 使用 createContext 同時生成組件
- 閉合標簽將組件包裹
Inner 組件
import React, { useContext } from 'react'
const value = useContext(CountContext)
function Inner(){
return (
<>
<p>{value}</p>
</>
)
}
export default Inner;
使用 useContext 來使用上下文
useReducer
用來實現類似 redux 功能
import React, { useReducer } from 'react';
function Demo(){
const [ count, dispatch ] = useReducer((state,action)=>{
switch(action){
case 'add':
return state+1
case 'sub':
return state-1
default:
return state
}
},0)
return (
<>
<h2>分數:{count}</h2>
<button onClick={()=>dispatch('add')}>加</button>
<button onClick={()=>dispatch('sub')}>減</button>
</>
)
}
export default Demo
- state 第一個參數 狀態
- action 控制業務邏輯的判斷參數
模擬 Redux
- useContext:可訪問全局狀態,避免一層層的傳遞狀態
- useReducer:通過action的傳遞,更新復雜邏輯的狀態
顏色共享組件 color.js
import React, { createContext,useReducer } from 'react';
export const ColorContext = createContext({})
export const UPDATE_COLOR = 'UPDATE_COLOR'
const reducer = (state, action) => {
switch(action.type){
case UPDATE_COLOR:
return action.color
default:
return state
}
}
export const Color = props => {
const [color, dispatch] = useReducer(reducer, 'blue')
return (
<ColorContext.Provider value = {{color,dispatch}}>
{props.children}
</ColorContext.Provider>
)
}
- 用 {props.children} 來顯示子組件
- 將 color 和 dispatch 共享出去
showArea.js
import React , { useContext } from 'react';
import { ColorContext } from './color';
function ShowArea(){
const { color } = useContext(ColorContext)
return (<div style={{ color:color }}>字體顏色為{ color }</div>)
}
export default ShowArea
- 注意 引入 ColorContext 使用了大括號
Buttons.js
import React , { useContext } from 'react';
import { ColorContext, UPDATE_COLOR } from './color'
function Buttons(){
const { dispatch } = useContext(ColorContext)
return (
<div>
<button onClick={()=>{dispatch({type:UPDATE_COLOR,color:"red"})}}>紅色</button>
<button onClick={()=>{dispatch({type:UPDATE_COLOR,color:"yellow"})}}>黃色</button>
</div>
)
}
export default Buttons
Demo.js
import React, { useReducer } from 'react';
import ShowArea from './ShowArea';
import Buttons from './Buttons';
import { Color } from './color'; //引入Color組件
function Demo(){
return (
<>
<Color>
<ShowArea />
<Buttons />
</Color>
</>
)
}
export default Demo
useMemo
用來解決使用 React hooks 產生的無用渲染的性能問題。
import React , {useState,useMemo} from 'react';
function Demo(){
const [xiaohong , setXiaohong] = useState('小紅待客狀態')
const [zhiling , setZhiling] = useState('志玲待客狀態')
return (
<>
<button onClick={()=>{setXiaohong(new Date().getTime())}}>小紅</button>
<button onClick={()=>{setZhiling(new Date().getTime()+',志玲向我們走來了')}}>志玲</button>
<ChildComponent name={xiaohong}>{zhiling}</ChildComponent>
</>
)
}
function ChildComponent({name,children}){
function changeXiaohong(name){
console.log('她來了,她來了。小紅向我們走來了')
return name+',小紅向我們走來了'
}
const actionXiaohong = changeXiaohong(name)
return (
<>
<div>{actionXiaohong}</div>
<div>{children}</div>
</>
)
}
export default Demo
點擊志玲按鈕,小紅對應的方法執行,雖然結果沒變,但是每次都執行,損耗性能。
function ChildComponent({name,children}){
function changeXiaohong(name){
console.log('她來了,她來了。小紅向我們走來了')
return name+',小紅向我們走來了'
}
const actionXiaohong = useMemo(()=>changeXiaohong(name),[name])
return (
<>
<div>{actionXiaohong}</div>
<div>{children}</div>
</>
)
}
第二個參數 [name] 匹配成功,才會執行。
useRef
- 用來獲取React JSX中的DOM元素
- 用來保存變量
import React, { useRef} from 'react';
function Demo(){
const inputEl = useRef(null)
inputEl.current.value = "給 input value屬性 賦值"
return (
<>
<input ref={inputEl} type="text"/>
</>
)
}
export default Demo
import React, { useRef, useState, useEffect } from 'react'
function Demo(){
const inputEl = useRef(null)
inputEl.current.value="給 input value屬性 賦值"
const [text, setText] = useState('默認值')
const textRef = useRef()
useEffect(()=>{
textRef.current = text
})
return (
<>
<input ref={inputEl} type="text"/>
<input value={text} onChange={(e)=>{setText(e.target.value)}} />
</>
)
}
export default Demo
- text 每次發生變化,將值保存到 useRef 中
- 使用 useEffect 實現每次狀態變化都進行變量重新賦值
- 很少用到這個功能(保存變量)
自定義 Hooks
編寫自定義函數實現獲取瀏覽器窗口
import React, { useState, useEffect, useCallback } from 'react';
function useWinSize(){
const [ size , setSize] = useState({
width:document.documentElement.clientWidth,
height:document.documentElement.clientHeight
})
const onResize = useCallback(()=>{
setSize({
width: document.documentElement.clientWidth,
height: document.documentElement.clientHeight
})
},[])
useEffect(()=>{
window.addEventListener('resize',onResize)
return ()=>{
window.removeEventListener('resize',onResize)
}
},[])
return size;
}
function Demo(){
const size = useWinSize()
return (
<div>頁面Size:{size.width} x {size.height}</div>
)
}
export default Demo
- 命名要使用 use 開頭以確認該函數是自定義 Hook 而不是組件
- useCallback 用來緩存方法 ( useMemo 是為了緩存變量)
- 第一次進入方法時用 useEffect 來注冊 resize 監聽事件
- 防止一直監聽所以在方法移除時,使用return的方式移除監聽
- 最后在 Demo 組件中使用
文章參考
- 官方文檔
- 嗶哩嗶哩up主技術胖的 視頻