React Hooks 笔记1

useState

const [state, setSate] = useState(initialState)

特征:

  • setState 标识稳定,组件重新渲染时不会变化,useState 返回的第一个值始终是最新的state

  • state 如果是对象,当只更新对象部分属性时,state更新不会合并对象

  • 如果 state 不发生变化,调用 setState 将跳过更新

建议:将同一时间段更新的 state, 组合初始化在一起

函数式初始化 state

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

更新 state 对象

setState((preState)=>{
    return {...prevState, ...updatedValues};
})

useEffect

useEffect 组件渲染之后异步执行回调,并在下次渲染前执行

useLayoutEffect 组件渲染之后同步执行回调

useEffect(callback)//组件每次渲染,都会重新生成 useEffect
useEffect(callback,[依赖参数])//组件每次渲染之后,根据依赖参数判断是否重新生成 useEffect
useEffect(callback,[]) // 只在组件挂载时运行一次

useEffect Hook 对应的生命周期:

  • componentDidMount

  • componentDidUpdate

  • componentWillUnmount

依赖项频繁变化措施(引用官方例子):

function Counter() {
  const [count, setCount] = useState(0);

  useEffect(() => {
    const id = setInterval(() => {
      setCount(c => c + 1); // ✅ setCount 函数式变更,没有依赖项
    }, 1000);
    return () => clearInterval(id);
  }, []); //

  return <h1>{count}</h1>;
}

useReducer

应用场景:

  • 管理内部 state

  • 结合 context,利用 dispatch 避免父组件向下传递回调

const TodosDispatch = React.createContext(null);
// 父组件
function TodosApp() {
  // 提示:`dispatch` 不会在重新渲染之间变化
  const [todos, dispatch] = useReducer(todosReducer);
  return (
    <TodosDispatch.Provider value={dispatch}>
      <DeepTree/>
    </TodosDispatch.Provider>
  );
}
// 子组件
function DeepTree(props) {
  // 获取 dispatch。
  const dispatch = useContext(TodosDispatch);

  function handleClick() {
    dispatch({ type: 'add', text: 'hello' });
  }

  return (
    <button onClick={handleClick}>Add todo</button>
  );
}

函数式初始化(引用官方例子)

function init(initialCount) {
  return {count: initialCount};
}

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);// 重新初始化 state,没用用到上一个state
    default:
      throw new Error();
  }
}

function Counter({initialCount}) {
  const [state, dispatch] = useReducer(reducer, initialCount, init);
  return (
    <>
      Count: {state.count}
      <button
        onClick={() => dispatch({type: 'reset', payload: initialCount})}> // 传入参数

        Reset
      </button>
      <button onClick={() => dispatch({type: 'decrement'})}>-</button>
      <button onClick={() => dispatch({type: 'increment'})}>+</button>
    </>
  );
}

useCallback

用于性能优化

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

useMemo

用于性能优化,传入的函数在组件渲染时执行

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

useRef

const refContainer = useRef(initialValue);
// refContainer 为 ref 对象
// refContainer.current 可以保存任何可变值

特征

  • useRef 每次渲染时返回同一个 ref 对象

  • 变更 .current 属性不会引发组件重新渲染

如何检测 DOM 元素的变化?(官方例子)

function MeasureExample() {
  const [height, setHeight] = useState(0);

  const measuredRef = useCallback(node => {
    if (node !== null) {
      setHeight(node.getBoundingClientRect().height);
    }
  }, []);// 检测 ref 的回调函数

  return (
    <>
      <h1 ref={measuredRef}>Hello, world</h1>
      <h2>The above header is {Math.round(height)}px tall</h2>
    </>
  );
}

自定义Hook

 

规则:函数必须以“use.."开头定义,内部可以调用其他Hook

应用场景:用于抽离共享逻辑和封装复杂的Hook

特征:

  • 不同组件共用自定义Hook,不会共享state

  • 组件可以多次调用自定义Hook

  • Hook之间可以传递信息(组件内的state传入自定义Hook,自定义Hook会随state变化而更新)

猜你喜欢

转载自www.cnblogs.com/seny-33/p/12219491.html