ReactJS -- hook

74 阅读2分钟

什么是hook函数

React Hook是特殊的内置函数, 可以在使用时在不编写class的情况下拥有状态(state)和副作用(side effects). 所有的hook函数都用use开头, 确保他们在组件的顶层被调用

hook函数解决了什么问题

  1. 简化逻辑复用
  2. 让代码更易理解和维护
  3. 为函数组件提供生命周期和创建状态

常见的的hook函数及其作用

useState

用于状态管理, 返回一个包含状态值和更新状态函数的数组, 可以更新这个数据的状态.

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

useEffect

用于执行副作用的操作, 集成了componentDidMount componentDidUpdate componentWillUnmounted三个钩子函数, 可以进行数据获取、监听事件、DOM操作等.

  const [data, setData] = useState([]);
  const [loading, setLoading] = useState(true);
  const [error, setError] = useState(null);

  useEffect(() => {
    // 定义一个异步函数来获取数据
    const fetchData = async () => {
      try {
        const response = await fetch('test link');
        if (!response.ok) {
          throw new Error('network error');
        }
        const result = await response.json();
        setData(result); // 更新状态
      } catch (error) {
        setError(error.message); // 捕获错误
      } finally {
        setLoading(false); // 完成加载
      }
    };

    fetchData(); // 调用异步函数
  }, []); 

useRef

用于访问DOM和保存可变数据, 可以操作元素或者组件对象, 或者在渲染周期中保存可变数据但不会重新渲染.

  const FocusInput = () => {
  const inputRef = useRef(null); // 创建一个 ref

  const handleFocus = () => {
    inputRef.current.focus(); // 使用 ref 聚焦输入框
  };

  return (
    <div>
      <input
        ref={inputRef} //  ref 赋值给输入框
        type="text"
      />
      <button onClick={handleFocus}>focus input</button>
    </div>
  );
};

useContext

用于共享状态, 子组件可以通过这个函数获取父组件传过来的context, 不需要显示的传递props.

  // 创建一个 Context
  const ThemeContext = createContext();

  const ThemeProvider = ({ children }) => {
    const [theme, setTheme] = useState('light'); // 默认主题为 light

    const toggleTheme = () => {
      setTheme(prevTheme => (prevTheme === 'light' ? 'dark' : 'light')); // 切换主题
    };

    return (
      <ThemeContext.Provider value={{ theme, toggleTheme }}>
        {children}
      </ThemeContext.Provider>
    );
  };

  const ThemedComponent = () => {
    const { theme, toggleTheme } = useContext(ThemeContext); // 使用 useContext 获取主题和切换函数

    return (
      <div style={{ background: theme === 'light' ? '#fff' : '#333', color: theme === 'light' ? '#000' : '#fff', padding: '20px' }}>
        <h1>Theme: {theme}</h1>
        <button onClick={toggleTheme}>ChangeTheme</button>
      </div>
    );
  };


useMemo

用于缓存计算结果, 在依赖项没有变化时, 避免重新计算.

  const ExpensiveComputation = ({ number }) => {
    // 一个耗时的计算
    const computeFactorial = (num) => {
      console.log('计算中...');
      return num <= 0 ? 1 : num * computeFactorial(num - 1);
    };

    // 使用 useMemo 缓存计算结果
    const factorial = useMemo(() => computeFactorial(number), [number]);

    return (
      <div>
        <h2>数字: {number}</h2>
        <h3>阶乘: {factorial}</h3>
      </div>
    );
  };

  const App = () => {
    const [number, setNumber] = useState(1);
    const [otherState, setOtherState] = useState(0);

    return (
      <div>
        <input
          type="number"
          value={number}
          onChange={(e) => setNumber(Number(e.target.value))}
        />
        <button onClick={() => setOtherState(otherState + 1)}>更新其他状态</button>
        <ExpensiveComputation number={number} />
      </div>
    );
  };

useCallback

用于缓存函数实例, 避免在每次渲染时创建新的函数实例.

  const Counter = ({ increment }) => {
    console.log('Counter 组件重新渲染');

    return (
      <div>
        <button onClick={increment}>add</button>
      </div>
    );
  };

  const App = () => {
    const [count, setCount] = useState(0);
    const [otherState, setOtherState] = useState(0);

    // 使用 useCallback 缓存 increment 函数
    const increment = useCallback(() => {
      setCount(prevCount => prevCount + 1);
    }, []);

    return (
      <div>
        <h1>当前计数: {count}</h1>
        <button onClick={() => setOtherState(otherState + 1)}>更新其他状态</button>
        <Counter increment={increment} />
      </div>
    );
  };