# hooks 16.8版本后

# 基础Hook

# useState

const [state, setState] = useState(initialState);

# useEffect

useEffect相当于 componentDidMount, componentDidUpdate, componentWillUnmount这三个生命周期函数的组合

useEffect(()=>{},[依赖项])
//第一个参数是一个回调函数,第二个参数是一个数组,这个数组中的元素都是依赖,每当依赖发生改变,就会触发第一个函数的执行

# useContext

React16中更新了Context API,Context主要用于爷孙组件的传值问题,新的Context API使用订阅发布者模式方式实现在爷孙组件中传值

React Hooks出现之后也对Context API出了响应的Hook useContext。同样也是解传值的问题

const stateContext = createContext('default');

//父组件
<stateContext.Provider
    value={"Hello React"}
>
    <ContextComponent/>
</stateContext.Provider>
//子组件 
const ContextComponent = () => {
    const value = useContext(stateContext);
    return (
        <>
            <h1>{value}</h1>
        </>
    );
}

# 额外Hook

# useReducer

更好的管理状态state 逻辑较复杂且包含多个子值,或者下一个 state 依赖于之前的 state等。 使用 useReducer 还能给那些会触发深更新的组件做性能优化,因为你可以向子组件传递 dispatch 而不是回调函数 。

const initialState = {count: 0};

function reducer(state, action) {
  switch (action.type) {
    case 'increment':
      return {count: state.count + 1};
    case 'decrement':
      return {count: state.count - 1};
    default:
      throw new Error();
  }
}

function Counter() {
  const [state, dispatch] = useReducer(reducer, initialState);
  return (
    <>
      Count: {state.count}
      <button onClick={() => dispatch({type: 'decrement'})}>-</button>
      <button onClick={() => dispatch({type: 'increment'})}>+</button>
    </>
  );
}

WARNING

React 会确保 dispatch 函数的标识是稳定的,并且不会在组件重新渲染时改变。这就是为什么可以安全地从 useEffect 或 useCallback 的依赖列表中省略 dispatch。

第三个参数(惰性初始化) useReducer的第三个参数接受一个函数作为参数,并把第二个参数当作函数的参数执行。主要作用是初始值的惰性求值,把一些对状态的逻辑抽离出来,有利于重置state。

const initialState = {count: 0};
function init(s) {
    console.log(s);
    return {...s};
}
function reducer(state, action) {
    switch (action.type) {
        case 'increment':
            return {count: state.count + 1};
        case 'decrement':
            return {count: state.count - 1};
        case 'reset':
            return init(action.payload);
        default:
            throw new Error();
    }
}
function Counter() {
    const [state, dispatch] = useReducer(reducer, initialState, init);
    return (
        <Fragment>
            Count: {state.count}
            <button onClick={() => dispatch({type: 'decrement'})}>-</button>
            <button onClick={() => dispatch({type: 'increment'})}>+</button>
            <button onClick={() => dispatch({type: 'reset', payload: initialState})}>重置</button>
        </Fragment>
    );
}

# useCallback

返回一个memoized回调函数
该回调函数仅在某个依赖项改变时才会更新

useCallback(fn, deps) 相当于 useMemo(() => fn, deps)。

const memoizedCallback = useCallback(
  () => {
    doSomething(a, b);
  },
  [a, b],
);

# useMemo

返回一个memoized值。

useMemo和useCallback很像,唯一不同的就是

公用的方法用useCallback,若是直接渲染值则用useMemo,用useCallback的话也是每次都要执行的,但是useMemo是直接把值记忆存储了(前面的都是废话,其实都能实现,不过这样更符合习惯)

const memoizedValue = useMemo(() => computeExpensiveValue(a, b), [a, b]);

# useRef

useRef返回一个可变的ref对象,其.current 属性被初始化为传入的参数(initialValue)。返回的ref对象在组件的整个生命周期内保持不变

const refContainer = useRef(initialValue);

# useImperativeHandle

useImperativeHandle可以让你在使用ref时自定义暴露给父组件的实例值。
应当避免使用ref这样的命令式代码。useImperativeHandle 应当与 forwardRef 一起使用:

//渲染<FancyInput ref={inputRef} /> 的父组件可以调用 inputRef.current.focus()。
function FancyInput(props, ref) {
  const inputRef = useRef();
  useImperativeHandle(ref, () => ({
    focus: () => {
      inputRef.current.focus();
    }
  }));
  return <input ref={inputRef} ... />;
}
FancyInput = forwardRef(FancyInput);

# useLayoutEffect

所有的DOM变更之后同步调用 effect。可以使用它来读取DOM布局并同步触发重渲染。
浏览器执行绘制之前,useLayoutEffect 内部的更新计划将被同步刷新。

# useDebugValue

可用于在 React 开发者工具中显示自定义 hook 的标签

暂时没用到过这个api

function useFriendStatus(friendID) {
  const [isOnline, setIsOnline] = useState(null);

  // ...

  // 在开发者工具中的这个 Hook 旁边显示标签
  // e.g. "FriendStatus: Online"
  useDebugValue(isOnline ? 'Online' : 'Offline');

  return isOnline;
}