hooks 注意點
- hooks 在使用時必須保證其調(diào)用順序醇锚,不能將 hooks 的調(diào)用放在 if for 等流程控制語句中哼御,也不能將 hooks 調(diào)用放在子函數(shù)中。
- hooks 只能放在 函數(shù)組件或自定義 hook 的最外層調(diào)用焊唬。
狀態(tài)鉤子 useState
- react 自帶一個 hook 函數(shù)恋昼,聲明組件狀態(tài)
- 參數(shù)可以設(shè)置 state 的初始值
- 返回值是一個只有兩個元素的數(shù)組[狀態(tài),狀態(tài)更新函數(shù)]
const [狀態(tài), 修改該狀態(tài)的方法] = useState(初始值)
注意
1赶促、在同一個函數(shù)中可以使用 useState 定義多個狀態(tài)
2液肌、useState 返回的狀態(tài)是一個引用類型,修改時鸥滨,只修改其中一個值嗦哆,并不會幫我們進行淺合并
3、useState 返回的 setState 方法同樣是異步方法 - 同樣會被批處理所監(jiān)管
副作用鉤子 useEffect
- 可以取代聲明周期函數(shù) componentDidMount婿滓、componentDidUpdate老速、componentWillUnmonent
- 給函數(shù)式組件添加副作用
- 副作用(Dom操作,數(shù)據(jù)請求)hook - 主要用來處理組件中的作用類型凸主,用于替代生命周期
useEffect(() => {
effect: 副作用函數(shù),
return(() => {
cleanup 清理函數(shù)
})
}, [input]) input: 依賴參數(shù)
- 掛載階段:從上到下執(zhí)行函數(shù)組件橘券,如果碰到 useEffect 就將其中的 effect 存儲到一個隊列中。當組件掛載完成之后卿吐,按照隊列順序執(zhí)行 effect 函數(shù)旁舰,并獲取 cleanup 函數(shù),存儲至一個新的隊列
- 更新階段:從上到下執(zhí)行函數(shù)組件嗡官,如果碰到 useEffect 就將其中的 effect 存儲到一個隊列中箭窜。當組件更新完成之后,會將之前存儲的 cleanup 函數(shù)隊列谨湘,按照順序執(zhí)行绽快。然后執(zhí)行 effect 隊列芥丧,并獲取 cleanup 函數(shù)紧阔,存儲至一個新的隊列。在更新階段會觀察依賴參數(shù)的值有沒有發(fā)生變化续担,如果沒有變化就不執(zhí)行對應(yīng)的 cleanup 和 effect擅耽。
- 卸載階段:找到之前存儲的 cleanup 函數(shù)隊列,依次執(zhí)行
useEffect 依賴參數(shù)給不同值的情況物遇;
- 情況一:為空或者為null
useEffect(() => {
console.log("useEffect");
});
這個時候乖仇,組件初始化憾儒、更新都會觸發(fā)。
- 情況二:依賴參數(shù)為空數(shù)組
useEffect(() => {
console.log("useEffect");
}, []);
這個時候乃沙,只有組件初始化會觸發(fā)起趾。
- 情況三:依賴參數(shù)
useEffect(() => {
console.log("useEffect");
}, [state]);
這個時候,組件初始化會執(zhí)行警儒、只要有一個依賴參數(shù)有變化更新都會觸發(fā)更新训裆。
注意:
useEffect 是延遲執(zhí)行的,如果想要同時執(zhí)行蜀铲,則需要用 useLayoutEffect
useLayoutEffect
和 useEffect 相識边琉,唯一的區(qū)別就是 useLayoutEffect 是同步執(zhí)行的。
使用場景:
一個對用戶可見的 DOM 變更就必須在瀏覽器執(zhí)行下一次繪制前被同步執(zhí)行记劝,這樣用戶才不會感覺到視覺上的不一致变姨。
useRef
語法 const refContainer = useRef(initialValue);
useRef 返回一個可變的 ref 對象,其 .current 屬性被初始化為傳入的參數(shù)(initialValue)厌丑。返回的 ref 對象在組件的整個生命周期內(nèi)持續(xù)存在定欧。
- useRef 除了可以保存實例之外,還可以保存組件更新前的一些數(shù)據(jù)
- 當 useRef 保存的是數(shù)據(jù)時怒竿,數(shù)據(jù)不會隨著組件的更新而自動更新忧额。一般可以用來保存一些接口的參數(shù) params
案例
function TextInputWithFocusButton() {
const inputEl = useRef(null);
const params = useRef({
name: "",
password: "",
});
const onButtonClick = () => {
// `current` 指向已掛載到 DOM 上的文本輸入元素
inputEl.current.focus();
};
return (
<>
<input ref={inputEl} type="text" />
<button onClick={onButtonClick}>Focus the input</button>
</>
);
}
useMemo
當依賴參數(shù)有變化時,執(zhí)行相應(yīng)函數(shù)愧口,并返回函數(shù)的返回值
案例
const [count,setCount] = useState(10);
const [num,setNum] = useState(1);
const applePrice = useMemo(() => {
console.log('觸發(fā)');
return count*18;
},[count]);
return <>
<div>count: {count}, 總價:{applePrice}元</div>
<button onClick={() => {
setCount(count+1);
}}>count+1</button>
<div>num: {num}</div>
<button onClick={() => {
setNum(num+1);
}}>num+1</button>
</>
useCallback
useCallback(fn, deps) 相當于 useMemo(() => fn, deps)睦番。
useContext
語法
const value = useContext(MyContext);
接收一個 context 對象
useContext(content) 相當于 <content.Consumer>
// index.js
const defaultContextValue = {
username: "dj",
};
// 創(chuàng)建一個context
const appContext = React.createContext(defaultContextValue);
// 根節(jié)點
ReactDOM.render(
<appContext.Provider value={defaultContextValue}>
<Robot />
</appContext.Provider>,
document.getElementById("root")
);
// 子組件
function Robot() {
const context = useContext(appContext);
return (
<p>{context.username}</p>
);
};
useReducer
語法
const [state, dispatch] = useReducer(reducer, initialArg, init);
useReducer 可以接收三個參數(shù),reducer耍属、initialArg托嚣、init。
- reducer 為 redux 的控制器厚骗;
- initialArg 為初始值示启;
- init 是一個方法,可以修改初始值想
案例
// 將字符串 "0" 變?yōu)?0
const init = (initArg) => {
return initArg - 0;
}
export default function HooksPage(props) {
const [state, dispatch] = useReducer(counterReducer, "0", init);
return (
<div>
<h3>HooksPage</h3>
<div>{state}</div>
<button onClick={() => dispatch({type: "ADD", payload: 1})}>add</button>
</div>
)
}
useImperativeHandle
語法 useImperativeHandle(ref, createHandle, [deps])
useImperativeHandle 可以讓你在使用 ref 時自定義暴露給父組件的實例值领舰。在大多數(shù)情況下夫嗓,應(yīng)當避免使用 ref 這樣的命令式代碼。useImperativeHandle 應(yīng)當與 forwardRef 一起
案例
function FancyInput(props, ref) {
const inputRef = useRef();
useImperativeHandle(ref, () => ({
focus: () => {
inputRef.current.focus();
}
}));
return <input ref={inputRef} ... />;
}
FancyInput = forwardRef(FancyInput);