這篇爲react hooks的學習筆記,僅對須要關注的重點作了記錄。有關react hooks詳細說明,參見官網https://reactjs.org/docs/hook...html
命名規範react
useState
useState 可傳任意類型的變量或者返回任意類型變量的 function。
useState 返回數組的第二個參數(setter),可傳任意類型的變量,或者一個接收 state 舊值的 function,其返回值做爲 state 新值redux
function Counter({ initialCount }) { const [count, setCount] = useState(initialCount); // Lazy initialization const [state, setState] = useState(() => { const initialState = someExpensiveComputation(props); return initialState; }); return ( <> Count: {count} <button onClick={() => setCount(0)}>Reset</button> <button onClick={() => setCount(prevCount => prevCount + 1)}>+</button> <button onClick={() => setCount(prevCount => prevCount - 1)}>-</button> </> ); }
set 方法不會像 setState 同樣作 merge,因此建議若是數據結構簡單,能夠將變量根據數據結構須要放在不一樣的 useState 中,避免大量使用相似{...state, value}形勢。若是數據結構複雜,建議使用 useReducer 管理組件的 state數組
useEffect瀏覽器
useEffect(effect, array);
effect 函數將在 componentDidAmount 時觸發和 componentDidUpdate 時有條件觸發。能夠返回一個函數(returnFunction),returnFunction 將會在 componentWillUnmount 時觸發和在 componentDidUpdate 時先於 effect 有條件觸發。
與 componentDidAmount 和 componentDidUpdate 不一樣之處是,effect 函數觸發時間爲在瀏覽器完成渲染以後。 若是須要在渲染以前觸發,須要使用 useLayoutEffect。
第二個參數 array 做爲有條件觸發狀況時的條件限制。數據結構
useContext
和consumer相似,仍然須要與Provider配合使用ide
const Context = React.createContext('light'); // Provider class Provider extends Component { render() { return ( <Context.Provider value={'dark'}> <DeepTree /> </Context.Provider> ) } }
// Consumer function Consumer(props) { const context = useContext(Context); return ( <div> {context} // dark </div> ); }
useReducer
用於管理複雜結構的狀態對象,與redux的核心邏輯一致。函數
const [state, dispatch] = useReducer(reducer, initialState, { type: 'reset', payload: initialCount });
// demo const TodosDispatch = React.createContext(null); function TodosApp() { // Tip: `dispatch` won't change between re-renders const [todos, dispatch] = useReducer(todosReducer, initialState); return ( <TodosDispatch.Provider value={dispatch}> <DeepTree todos={todos} /> </TodosDispatch.Provider> ); }
useCallback
useCallback和下面的useMemo是很是實用的提高性能的小工具。工具
const memoizedCallback = useCallback( () => { doSomething(a, b); }, [a, b] );
useCallback返回一個memoized函數,在參數a和b都沒有改變時,老是返回同一個函數。
其具體實現邏輯基本以下:性能
let memoizedState = null; function useCallback(callback, inputs) { const nextInputs = inputs !== undefined && inputs !== null ? inputs : [callback]; const prevState = memoizedState; if (prevState !== null) { const prevInputs = prevState[1]; if (areHookInputsEqual(nextInputs, prevInputs)) { return prevState[0]; } } memoizedState = [callback, nextInputs]; return callback; }
注:第二個參數目前只用於指定須要判斷是否變化的參數,並不會做爲形參傳入回調函數。建議回調函數中使用到的變量都應該在數組中列出。之後的版本可能會將第二項數組參數移除,自動判斷回調函數中使用到的變量是否變化來判斷返回結果。
useMemo
const memoizedValue = useMemo(() => computeExpensiveValue(a, b), [a, b]);
與useCallback相似,返回一個memoized函數執行結果。
useMemo(() => fn, inputs) 等價於 useCallback(fn, inputs)
useMemo可用於實現PureComponent子組件:
function Parent({ a, b }) { // Only re-rendered if `a` changes: const child1 = useMemo(() => <Child1 a={a} />, [a]); // Only re-rendered if `b` changes: const child2 = useMemo(() => <Child2 b={b} />, [b]); return ( <> {child1} {child2} </> ) }
useRef
const refContainer = useRef(initialValue);
相似 react.createRef()。
在使用hooks的function component中,useRef不只能夠用來作DOM的引用,還能夠作來做爲相似class的實例屬性,由於相同位置的useRef()每次返回的都是同一個對象。
function Timer() { const intervalRef = useRef(); useEffect(() => { const id = setInterval(() => { // ... }); intervalRef.current = id; return () => { clearInterval(intervalRef.current); }; }); // ... }
利用useRef()的這種特性,還能夠作不少其餘有趣的事情,例如獲取previous props或previous state:
function Counter() { const [count, setCount] = useState(0); const prevCountRef = useRef(); useEffect(() => { prevCountRef.current = count; }); const prevCount = prevCountRef.current; return <h1>Now: {count}, before: {prevCount}</h1>; }
useImperativeMethods
function FancyInput(props, ref) { const inputRef = useRef(); useImperativeMethods(ref, () => ({ focus: () => { inputRef.current.focus(); } })); return <input ref={inputRef} ... />; } FancyInput = React.forwardRef(FancyInput);
useImperativeMethods提供了父組件直接調用子組件實例方法的能力。
上例中,一個包含 <FancyInput ref={fancyInputRef} />
的父組件,就能夠調用 fancyInputRef.current.focus().
用React.memo來實現shouldComponentUpdate。
const Button = React.memo((props) => { // your component });