记录ReactHook的使用

303 阅读3分钟

记录ReactHook的使用

useMemo

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

把创建函数和依赖项数组作为参数传入useMemo,会再某个依赖项发生变化时重新计算。这种优化有助于避免每次渲染时都进行高开销的计算。(备注:第一个参数:功能上类似于vue的watch或computed。第二个参数:类似shouldComputedUpdate)

传入useMome的函数会在渲染期间执行,不要在函数内部执行与渲染无关的操作,如副作用操作,这类操作属于useEffect的范畴。

useMome 主要是为优化性能

useEffect

useEffect(didUpdate)

useEffect可以接收一个包括命令,且可能有副作用代码的函数。 副作用包括:改变DOM、添加订阅、设置定时器、记录日志等

清除effect

通常,组件卸载时需要清除effect创建的诸如订阅或计时器ID等资源。要实现这一点,useEffect函数需返回一个清除函数。

useEffect(() => {
  const subscription = props.source.subscribe();
  return () => {
    subscription.unsubscribe();
  }
})

为防止内存泄漏,清除函数会在组件卸载前执行。另外,组件多次渲染也是如此。

effect的执行机制

与componentDidMount、componentDidUpdate不同的是,传给useEffect的函数会在浏览器完成布局与绘制之后,在一个延迟事件中被调用。这使得它适用于许多常见的副作用场景,比如设置订阅和事件处理等情况,因为绝大多数的操作不应阻塞浏览器对屏幕的更新。

并不是所有effect都可以被延迟执行。例如:一个对用户可见的DOM变更就必须在浏览器执行下一次绘制前同步执行,这样用户才不会感觉视觉上的不一致。Rect提供了一个额外的useLayoutEffect Hook来处理这类effect。它和useEffect的结构相同,区别只是调用时机不同。(备注:useEffect类似于setTimeOut函数与Promise的执行机制)

effect的条件执行

默认情况,effect会在每轮组件渲染后执行。 useEffect支持第二个参数,它是effect所依赖的值数组。在依赖的值变化时执行。

useEffect(
  () => {
    const subscription = props.source.subscribe();
    return () => {
      subscription.unsubscribe();
    }
  },[props.source],
)

如果effect只想执行一次,可以传递一个空数组。告诉Rect effect不依赖与props或state中的任何值。

useLayoutEffect

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

useState

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

返回一个state,以及更新state的函数。

惰性初始state

useState可以接收一个函数

const [state, setState] = useState(() =>{
  const initialState = sumeExpensiveComputation(props);
  return initialState
})

useContext

const value = useContext(MyContext)

接收一个context对象(React.createContext的返回值)并返回该context的当前值。当前值的context值由上层组件中距离最近的<MyContext.Provider>的value prop决定。

当组件上层最近的<MyContext.Provider>更新时,该Hook会触发渲染,并使用最新传递给MyContext provider的context value值。即使祖先使用React.memo或shouldComponentUpdate,也会在组件本身使用useContext时重新渲染。

useReducer

const [state, dispatch] = useReducer(reducer, initialArg, init)

useState的替代方案。

const initialState = { count: 0 };
function reducer(state, action){
  switch(action.type){
    case 'increment':
      return { count: state.conut + 1}
    case 'decrement':
      return { count: state.count - 1}
    default:
      throw new Error();
  }
}
function Counter(){
  const [state, dispatch] = useReducer(reducer, initailState);
  return (
    <>
      Count: { state.count }
      <button onClick = { () => dispatch({type: 'decrement'})}>-</button>
      <button onClick = { () => dispatch({type: 'increment'})}>+</button>
    </>
  )
}

useCallback

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

返回一个memoized回调函数。 useCallback(fn, deps)相当于useMemo(() => fn, deps)

useRef

const refContainer = useRef(initialValue)

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

function TextInputWithFocusButton() {
  const inputE1 = useRef(null);
  const onButtonClick = () => {
    inputE1.current.focus();
  }
  return (
    <>
      <input ref = { inputE1 } type = "text" />
      <button onClick = { onButtonClick }>Focus the input</button>
    </>
  )
}