009编程技术分享

React Hooks入门与实践

发布于 2023年9月28日

React Hooks是React 16.8版本引入的新特性,它允许你在不编写class的情况下使用state以及其他的React特性。本文将从基础概念开始,逐步深入到自定义Hooks的创建和使用。

什么是React Hooks?

Hooks是一些可以让你在函数组件里"钩入"React state及生命周期等特性的函数。Hooks不能在class组件中使用,这让你不使用class也能使用React。

基本Hooks

useState

useState是最基本的Hook,它让你能够在函数组件中添加state。

import React, { useState } from 'react';

function Counter() {
  // 声明一个新的state变量,我们将其称为"count"
  const [count, setCount] = useState(0);

  return (
    

你点击了 {count} 次

); }

useState接收一个初始state值作为参数,并返回一个数组,其中第一个元素是当前的state值,第二个元素是一个更新state的函数。

useEffect

useEffect让你可以在函数组件中执行副作用操作(如数据获取、订阅或手动更改DOM)。

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

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

  // 相当于componentDidMount和componentDidUpdate
  useEffect(() => {
    // 更新文档标题
    document.title = `你点击了 ${count} 次`;
    
    // 可选的清理函数
    return () => {
      // 在组件卸载或重新渲染前执行清理
      // 这里可以清除定时器、取消订阅等
    };
  }, [count]); // 仅在count改变时重新执行effect

  return (
    

你点击了 {count} 次

); }

useEffect接收两个参数:一个函数和一个依赖数组。依赖数组是可选的,如果省略,effect会在每次渲染后都执行;如果提供,effect只会在依赖项发生变化时执行。

useContext

useContext让你可以在组件中访问React的Context,无需通过组件树逐层传递props。

import React, { useContext } from 'react';

// 创建一个Context
const ThemeContext = React.createContext('light');

function ThemedButton() {
  // 使用useContext访问Context
  const theme = useContext(ThemeContext);
  
  return (
    
  );
}

function App() {
  return (
    
      
    
  );
}

额外的Hooks

useReducer

useReduceruseState的替代方案,用于管理复杂的state逻辑。

import React, { useReducer } from 'react';

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, { count: 0 });

  return (
    

Count: {state.count}

); }

useMemo

useMemo用于性能优化,它可以缓存计算结果,避免在每次渲染时重复计算。

import React, { useState, useMemo } from 'react';

function ExpensiveComponent({ a, b }) {
  // 只有当a或b改变时才会重新计算
  const result = useMemo(() => {
    console.log('执行昂贵的计算');
    return a * b;
  }, [a, b]);

  return 
计算结果: {result}
; }

useCallback

useCallbackuseMemo类似,但它缓存的是函数本身,而不是计算结果。

import React, { useState, useCallback } from 'react';

function Button({ onClick }) {
  console.log('Button重新渲染');
  return ;
}

function Parent() {
  const [count, setCount] = useState(0);
  const [text, setText] = useState('');

  // 只有当count改变时,onClick函数才会重新创建
  const onClick = useCallback(() => {
    console.log(`Count: ${count}`);
  }, [count]);

  return (
    
setText(e.target.value)} />

Count: {count}

); }

自定义Hooks

自定义Hooks允许你将组件逻辑提取到可重用的函数中。自定义Hook是一个函数,其名称以"use"开头,可以在其中调用其他Hook。

创建自定义Hook

import { useState, useEffect } from 'react';

function useWindowSize() {
  // 声明state来存储窗口尺寸
  const [windowSize, setWindowSize] = useState({
    width: undefined,
    height: undefined,
  });

  useEffect(() => {
    // 处理窗口尺寸变化的函数
    function handleResize() {
      setWindowSize({
        width: window.innerWidth,
        height: window.innerHeight,
      });
    }

    // 添加事件监听器
    window.addEventListener('resize', handleResize);
    
    // 初始化
    handleResize();

    // 清理函数
    return () => window.removeEventListener('resize', handleResize);
  }, []); // 空依赖数组意味着这个effect只会在组件挂载和卸载时运行

  return windowSize;
}

// 使用自定义Hook
function App() {
  const size = useWindowSize();

  return (
    

窗口宽度: {size.width}

窗口高度: {size.height}

); }

自定义Hook案例:数据获取

import { useState, useEffect } from 'react';

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

  useEffect(() => {
    // 重置状态
    setLoading(true);
    setError(null);

    // 执行fetch
    fetch(url)
      .then(response => {
        if (!response.ok) {
          throw new Error('网络请求失败');
        }
        return response.json();
      })
      .then(data => {
        setData(data);
        setLoading(false);
      })
      .catch(error => {
        setError(error);
        setLoading(false);
      });
  }, [url]);

  return { data, loading, error };
}

// 使用数据获取Hook
function UserList() {
  const { data: users, loading, error } = useFetch('https://api.example.com/users');

  if (loading) return 
加载中...
; if (error) return
错误: {error.message}
; return (
    {users.map(user => (
  • {user.name}
  • ))}
); }

Hook使用规则

使用React Hooks时需要遵循两条重要规则:

  1. 只在函数组件的顶层调用Hook:不要在循环、条件或嵌套函数中调用Hook
  2. 只在React函数组件或自定义Hook中调用Hook:不要在普通JavaScript函数中调用Hook

总结

React Hooks为函数组件提供了强大的功能,使我们能够在不使用class的情况下编写具有状态和副作用的组件。通过组合使用内置Hooks和创建自定义Hooks,我们可以构建更加模块化、可重用和易于测试的React应用程序。

在实际开发中,建议尽可能使用Hooks来编写组件,因为它们通常会使代码更加简洁和易于理解。同时,也要注意遵循Hooks的使用规则,以避免潜在的问题。

返回首页