发布于 2026-01-06 1 阅读
0

React Hooks 简明教程(包含数据获取、自定义 Hooks、Context 和用法)概述 useState useEffect useContext Hooks 规则 自定义 Hooks

React Hooks 简明教程(包括数据获取、自定义 Hooks、上下文和用法)

概述

使用状态

使用效果

useContext

钩子规则

定制挂钩

所以,我尝试为那些刚接触 hooks 的人提供一个快速概览,介绍你应该了解的最重要的 hooks,并提供每个 hooks 的基本使用示例,帮助你入门。

现在我们出发。

替代文字

概述

钩子函数试图解决多个(看似不相关的)问题,但为了尽可能简洁,您应该知道钩子函数允许您:

  • 在你的函数组件中设置状态
  • 在多个组件中重用一段状态逻辑
  • 逻辑过于复杂时,请简化它。

让我们从第一个钩子开始。

使用状态

useState 是 Hooks 中在函数组件中管理状态的方法。例如,假设你要实现一个掌声计数器,通常会通过实现一个基于类的组件来实现,如下所示:

class Example extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      claps: 0
    };
  }

  render() {
    return (
      <div>
        <p>You clicked {this.state.claps} times</p>
        <button onClick={() => this.setState({ claps: this.state.claps + 1 })}>
          Clap
        </button>
      </div>
    );
  }
}
Enter fullscreen mode Exit fullscreen mode

在 Hooks 中,你也可以通过编写以下代码来实现同样的功能:

function Example() {
  const [claps, setClaps] = useState(0);

  return (
    <div>
      <p>You clapped {claps} times</p>
      <button onClick={() => setClaps(claps + 1)}>
        Clap
      </button>
    </div>
  );
}
Enter fullscreen mode Exit fullscreen mode

瞧,你就得到了一个功能齐全的状态(双关语)。
这行代码使用了数组解构,这是ES6const [claps, setClaps] = useState(0);中引入的。

claps是我们的状态字段,它的初始值是我们传递给 `calls` 的任何值useState,在本例中为 `0` 0,因此 `calls` 的初始值将等于 `0`。0

setClaps我们将使用这个函数来修改claps状态字段。正如你所看到的,当我们点击鼓掌按钮时,会触发该函数onClick,并setClaps调用另一个函数,传入现有值claps“加号” 1,该值将成为claps字段的新值。

第一个钩子就此完成!

替代文字

使用效果

useEffect钩子可以用来模拟许多现有的生命周期方法,例如 `get_lifecycle()`componentDidMount` get_lifecycle()` (当然也包括一些较旧的生命周期方法,例如 `get_lifecycle( )`)。componentWillUnmountcomponentDidUpdatecomponentWillRecieveProps

但在查看使用示例之前,您应该知道它useEffect接受两个参数,一个函数和一个数组。

该数组(我们称之为依赖项数组)将包含值的名称,当这些值发生更改时,函数(即第一个参数)将被调用。

如果没有依赖关系数组怎么办?

  • 这意味着 useEffect 函数(它的第一个参数)会在每次渲染时运行,这通常不是我们想要的结果。

在后面的例子中,我们会提到当依赖数组为空时会发生什么情况。

对状态/属性变化做出反应

我们来看一个例子。

假设你想在用户每次鼓掌时执行某些操作,例如,你想显示console.log“你鼓掌了”的消息,useEffect我们可以用钩子函数来实现这一点。

function Example() {
  const [claps, setClaps] = useState(0);

  useEffect(()=>{
     console.log("You clapped");
  },[claps])

  return (
    <div>
      <p>You clapped {claps} times</p>
      <button onClick={() => setClaps(claps + 1)}>
        Clap
      </button>
    </div>
  );
}
Enter fullscreen mode Exit fullscreen mode

所以,这里发生的情况是,每次状态字段发生变化时,React 都会检查我们所有的 useEffect(是的,我们的代码中可以有多个 useEffect,就像可以使用 `useEffect` 定义多个状态字段一样useState),并触发所有useEffect依赖数组中包含已更改字段的函数。

所以,在我们的例子中,当我们点击鼓掌按钮时,该setClaps函数会被调用,claps状态字段会发生变化,这会导致 useEffect 的第一个参数(即它的函数)被调用,因为它的依赖数组包含该claps字段。

    ...
    useEffect(()=>{
       console.log("You clapped");
    },[claps])

    ...
Enter fullscreen mode Exit fullscreen mode

所以,这基本上就是模拟的方法。componentDidUpdate

当然,这种结构也可以用于在 prop 更改时调用 useEffect hook 函数,只需将您希望考虑的任何 prop 添加到依赖项数组中即可。例如,如果拍手次数是从组件的父组件获取的:

function({claps}){
    useEffect(()=>{
       console.log("You clapped");
    },[claps])
    ...
}
Enter fullscreen mode Exit fullscreen mode

另外,由于它被称为依赖数组,请记住它可以包含多个值,并且当依赖数组中的一个或多个值发生更改时,该函数将被触发。

数据获取

useEffect 也可以用来获取数据,但在使用此钩子获取数据之前,需要问的关键问题是:

如果依赖项数组为空会怎样?

  • 这意味着钩子不会在每次渲染时运行,因为我们明确告诉它不要监视任何变量,所以它只会在挂载时运行。

这通常是我们想要获取数据时所需要的。

替代文字

既然我们已经知道如何让 useEffect 只在组件挂载时运行(模拟 componentDidMount 生命周期),那么获取数据就变得非常简单,只需这样做:

    function App(){
      const [data,setData] = useState([]);

      useEffect(()=>{
       const data = await axios('https://datafetchingexample/data');
       setData(data);
      },[])

      ...
    }

Enter fullscreen mode Exit fullscreen mode

清理

替代文字

接下来,我们需要弄清楚如何使用useEffect它在组件中执行任何我们想要进行的清理工作。

    function App(){
      const [data,setData] = useState([]);

      useEffect(()=>{
        const source = axios.CancelToken.source();

        const data = await axios('https://datafetchingexample/data');
        setData(data);

        return () => {
          source.cancel();
        };

      },[])


      ...
    }

Enter fullscreen mode Exit fullscreen mode

正如您可能已经注意到的,我们在钩子函数中添加了一个返回值,该返回函数将在组件卸载时运行,使其成为进行任何清理工作(关闭套接字、取消订阅、取消请求等……基本上与 componentWillUnMount 的用法相同)的理想位置。

useContext

接下来,我们将探讨如何使用上下文和钩子。

替代文字

如你所知,Context 是 React 用于管理组件间状态的一种方式,它本质上是 React 自己的 Redux。

当你在组件中有一些数据,并且希望该组件的后代(直接子组件或一般的间接子组件)能够访问这些数据时,就会用到上下文。例如,假设我们有一个组件获取数据,并且你想将这些数据传递给你的子组件,很显然的方法是使用 props,但是如果你想让你的子组件(甚至更远的子组件)也能访问这些数据……这时使用 props 就会变得很麻烦,而使用上下文则更有意义。

为了便于解释,假设你想把这些数据传递给你的直系子女。

首先,我们创建一个值为空对象的上下文。
const DataContext = React.createContext({});
接下来,你应该将要传递上下文的组件包裹起来。我们
<DataContext value=somevalue></DataContext>
对子组件就是这么做的。我们只需要通过 value 属性确定上下文的值
(在本例中,我们要传递数据字段),所以我们这样做了。

    ...

    const DataContext = React.createContext({});

    function App(){
      const [data,setData] = useState([]);

      useEffect(()=>{
        const source = axios.CancelToken.source();

        const data = await axios('https://datafetchingexample/data');
        setData(data);

        return () => {
          source.cancel();
        };

      },[])


      return (

         <DataContext value={{data}}>
           <Child/>
         </DataContext>

      )
    }

Enter fullscreen mode Exit fullscreen mode

现在来看我们的子组件,我们只需要使用useContext钩子函数,将我们需要的上下文对象传递给它,然后获取我们在value属性中添加的数据即可。

    ...


    function Child(){
      const {data} = useContext(DataContext);


      return (

         <ul>
           data.map(v=>{
             return (
               <li>
                 {v.value}
               </li>
             )
           })
         </ul>

      )
    }

Enter fullscreen mode Exit fullscreen mode

既然我们已经介绍了三种最常用的鱼钩,接下来让我们谈谈鱼钩的一般规则。

钩子规则

只在最高层调用钩子

这意味着你应该在循环、if 条件语句或嵌套函数中使用 Hooks,而应该始终在 React 函数的顶层使用。这是因为 Hooks 的执行依赖于它们的初始化顺序。例如,如果你在 if 条件语句中将另一个 Hooks 嵌套在另一个 Hooks 中,那么该 if 条件语句在下一次渲染时可能不会执行,从而导致 Hooks 执行混乱。我们将在另一篇文章中详细讨论这个问题。

不要在 JavaScript 函数中调用钩子函数

你可以从两个地方呼叫钩子

  • React 功能组件
  • 接下来我们将讨论自定义钩子。

定制挂钩

替代文字

现在来说说 React Hooks 的最后一个也是核心部分:创建自定义 Hooks。

自定义钩子是名称以 `.hook` 开头的 JavaScript 函数use,它能够调用其他钩子(自定义的或内置的)。

构建自定义钩子意味着您可以提取一段逻辑,以便在多个地方使用。例如,假设您有两个输入框,分别接受姓名和年龄。


function InputForm(){
  const [name,setName] = useState("")
  const [age,setAge] = useState(0)

  return (
    <div>
       <input type="text" placeholder="Enter your name" value={name} onChange={(e)=>setName(e.target.value)/>
       <input type="number" placeholder="Enter your age" value={age} onChange={(e)=>setAge(e.target.value)}/>

    </div>

  )

}
Enter fullscreen mode Exit fullscreen mode

现在,我们应用中的所有输入框基本上都具有类似的结构:包含值和 onChange 属性的输入字段。不仅在这个文件中,我们还可以在多个文件中使用状态来处理输入。自定义钩子允许我们提取可重用的逻辑并在其他地方使用。

它看起来大概是这样的:


function useFormInput(initialValue){
  const [value,setValue] = useState(initialValue);
  function onChange(e){
    setValue(e.target.value);
  }
  return {value,onChange};

}

function InputForm(){
  const name = useFormInput("")
  const age = useFormInput(0)

  return (
    <div>
       <input type="text" placeholder="Enter your name" {...name} />
       <input type="number" placeholder="Enter your age" {...age} />
    </div>

  )

}
Enter fullscreen mode Exit fullscreen mode

更简洁吧?这和常规方法的效果一样,但现在你有了可重用的钩子,可以在应用程序的任何位置使用功能可变的输入框。只需使用钩子,解构输入标签中返回的值,就可以了!

如果你觉得在完成 4 个项目的同时还需要更多练习,我建议你看看这门课程:

https://www.udemy.com/course/react-hooks-projects-course/

文章来源:https://dev.to/bitpunchz/react-hooks-in-a-nutshell-4llg