loading

【React】react hooks

如果你感觉很累,那说明你在走上坡路 -->

# 注意点

  • Hook 是向下兼容的,类组件中不可以使用
  • 只能在函数最外层调用 Hook。不要在循环、条件判断或者子函数中调用。(有 lint 插件可以校验)
  • 只能在 React 的函数组件中调用 Hook。不要在其他 JavaScript 函数中调用。

# 官方 Hook API 文档

https://zh-hans.reactjs.org/docs/hooks-reference.html (opens new window)

# useState

useState 会返回一对值:当前状态和一个让你更新它的函数,你可以在事件处理函数中或其他一些地方调用这个函数。它类似 class 组件的 this.setState,useState 唯一的参数就是初始 state

const [count, setCount] = useState(0);
1

如果初始 state 需要通过复杂计算获得,则可以传入一个函数

const [state, setState] = useState(() => {
  const initialState = someExpensiveComputation(props);
  return initialState;
});
1
2
3
4

# useEffect

当你调用 useEffect 时,就是在告诉 React 在完成对 DOM 的更改后运行你的“副作用”函数。由于副作用函数是在组件内声明的,所以它们可以访问到组件的 props 和 state

和 componentDidMount、componentDidUpdate 和 componentWillUnmount 具有相同的用途,只不过被合并成了一个 API。

import React, { useState, useEffect } from "react";

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

  // 相当于 componentDidMount 和 componentDidUpdate:
  useEffect(() => {
    // 使用浏览器的 API 更新页面标题
    document.title = `You clicked ${count} times`;
  });

  return (
    <div>
      <p>You clicked {count} times</p>
      <button onClick={() => setCount(count + 1)}>Click me</button>
    </div>
  );
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18

useEffect 还可以通过返回一个函数来指定如何“清除”副作用,类似于在 componentWillUnmount 干的事情

# useEffect 第二个参数

import * as React from "react";

const App: React.FC = () => {
  const [count, setCount] = React.useState(0);
  React.useEffect(() => {
    console.log("effect");
    return () => {
      console.log("returnFunction");
    };
  }, [count]);
  return (
    <>
      <div>{count}</div>
      <button onClick={() => setCount(count + 1)}>count++</button>
    </>
  );
};

export default App;
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
  • 空,则每次 componentDidUpdate 时都会 先触发 returnFunction(如果存在),再触发 effect
  • [] 模拟 componentDidMount, returnFunction 模拟 componentWillUnMount
  • [id] 仅在 id 的值发生变化以后触发, 先触发 returnFunction(如果存在),再触发 effect

# useContext

定义:const value = useContext(MyContext);

使用:<MyContext.Provider>

const themes = {
  light: {
    foreground: "#000000",
    background: "#eeeeee",
  },
  dark: {
    foreground: "#ffffff",
    background: "#222222",
  },
};

const ThemeContext = React.createContext(themes.light);

function App() {
  return (
    <ThemeContext.Provider value={themes.dark}>
      <Toolbar />
    </ThemeContext.Provider>
  );
}

function Toolbar(props) {
  return (
    <div>
      <ThemedButton />
    </div>
  );
}

function ThemedButton() {
  const theme = useContext(ThemeContext);
  return (
    <button style={{ background: theme.background, color: theme.foreground }}>
      I am styled by theme context!
    </button>
  );
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37

# useReducer

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>
    </>
  );
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23

# useCallback

返回一个有缓存的函数,类似函数柯里化.useCallback(fn, deps) 相当于 useMemo(() => fn, deps)

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

# useMemo

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

把“创建”函数和依赖项数组作为参数传入 useMemo,它仅会在某个依赖项改变时才重新计算 memoized 值。这种优化有助于避免在每次渲染时都进行高开销的计算

# useRef

useRef 返回一个可变的 ref 对象

function TextInputWithFocusButton() {
  const inputEl = useRef(null);
  const onButtonClick = () => {
    // `current` 指向已挂载到 DOM 上的文本输入元素
    inputEl.current.focus();
  };
  return (
    <>
      <input ref={inputEl} type="text" />
      <button onClick={onButtonClick}>Focus the input</button>
    </>
  );
}
1
2
3
4
5
6
7
8
9
10
11
12
13

# useImperativeHandle

# useLayoutEffect

# useDebugValue

# 自定义 Hook

自定义 Hook 更像是一种约定而不是功能。如果函数的名字以 “use” 开头并调用其他 Hook,我们就说这是一个自定义 Hook。 useSomething 的命名约定可以让我们的 linter 插件在使用 Hook 的代码中找到 bug。

# 参考

最近更新时间: 2021/06/17 10:13:36
最近更新
01
2023/07/03 00:00:00
02
2023/04/22 00:00:00
03
2023/02/16 00:00:00