React Hooks (一文看懂四个常用的钩子)

news/2024/7/15 17:12:43 标签: react.js, javascript, typescript

React Hooks (一文看懂四个常用的钩子)

上次看了阮一峰老师的文章,写的很通俗易懂,我在这简单给大家梳理一下

我们在开发中常用的就以下四个Hooks。

  1. useState()
  2. useContext()
  3. useReducer()
  4. useEffect()

1、useState():状态钩子

useState()用于为函数组件引入状态(state)。纯函数不能有状态,所以把状态放在钩子里面。
const [num,setNum] = useState<number>(1)
这一句代码是用白话说就是有个num变量,必须是number类型的(<>尖括号里边的是TYpescript限制类型的写法),初始值为一个数字1,然后setNum就是一个方法,通过一个前缀set就能看出来。setNum(10),通过set了一下,num的值就为10了。

<div onClick= {()=>setNum(10)}>

再看一个例子

import React, { useState } from "react";

export default function  Button()  {
  const  [buttonText, setButtonText] =  useState("Click me,   please");

  function handleClick()  {
    return setButtonText("Thanks, been clicked!");
  }

  return  <button  onClick={handleClick}>{buttonText}</button>;
}

上面代码中,Button 组件是一个函数,内部使用useState()钩子引入状态。

useState()这个函数接受状态的初始值,作为参数,上例的初始值为按钮的文字。该函数返回一个数组,数组的第一个成员是一个变量(上例是buttonText),指向状态的当前值。第二个成员是一个函数,用来更新状态,约定是set前缀加上状态的变量名(上例是setButtonText)。

2、useContext():共享状态钩子

如果一个父组件有两个子组件,现在这两个子组件之间需要共享状态,就可以使用useContext

现在有两个组件 Navbar 和 Messages,我们希望它们之间共享状态。

<div className="App">
  <Navbar/>
  <Messages/>
</div>

第一步就需要使用React Context API,在组件外部建一个Context。

const AppContext = React.creactContext({})

组件封装代码如下


<AppContext.Provider value={{
  username: 'superawesome'
}}>
  <div className="App">
    <Navbar/>
    <Messages/>
  </div>
</AppContext.Provider>

上面代码中,AppContext.Provider提供了一个 Context 对象,这个对象可以被子组件共享。

在组件 Navbar 和 Messages中,我们可以通过使用const {username} = useContext(AppContext),拿到父组件的username了

const Navbar = () => {
  const { username } = useContext(AppContext);
  return (
    <div className="navbar">
      <p>AwesomeSite</p>
      <p>{username}</p>
    </div>
  );
}

3、useReducer():action 钩子

React 本身不提供状态管理功能,通常需要使用外部库。这方面最常用的库是 Redux。

Redux 的核心概念是,组件发出 action 与状态管理器通信。状态管理器收到 action 以后,使用 Reducer 函数算出新的状态,Reducer 函数的形式是(state, action) => newState

useReducers()钩子用来引入 Reducer 功能。

const [state, dispatch] = useReducer(reducer, initialState);

上面是**useReducer()的基本用法,它接受 Reducer 函数和状态的初始值作为参数,返回一个数组。数组的第一个成员是状态的当前值,第二个成员是发送**action 的dispatch函数。

下面是一个计数器的例子。用于计算状态的 Reducer 函数如下。

const myReducer = (state, action) => {
  switch(action.type)  {
    case('countUp'):
      return  {
        ...state,
        count: state.count + 1
      }
    default:
      return  state;
  }
}

组件代码如下。

function App() {
  const [state, dispatch] = useReducer(myReducer, { count:   0 });
  return  (
    <div className="App">
      <button onClick={() => dispatch({ type: 'countUp' })}>
        +1
      </button>
      <p>Count: {state.count}</p>
    </div>
  );
}

4、useEffect():副作用钩子

什么是副作用?
看到这里,你可能会产生一个疑问:如果纯函数只能进行数据计算,那些不涉及计算的操作(比如生成日志、储存数据、改变应用状态等等)应该写在哪里呢?
函数式编程将那些跟数据计算无关的操作,都称为 “副效应” (side effect) 。如果函数内部直接包含产生副效应的操作,就不再是纯函数了,我们称之为不纯的函数。
纯函数内部只有通过间接的手段(即通过其他函数调用),才能包含副效应。

useEffect()本身是一个函数,由 React 框架提供,在函数组件内部调用即可。

举例来说,我们希望组件加载以后,网页标题(document.title)会随之改变。那么,改变网页标题这个操作,就是组件的副效应,必须通过useEffect()来实现。

import React, { useEffect } from 'react';

function Welcome(props) {
  useEffect(() => {
    document.title = '加载完成';
  });
  return <h1>Hello, {props.name}</h1>;
}

上面例子中,useEffect()的参数是一个函数,它就是所要完成的副效应(改变网页标题)。组件加载以后,React 就会执行这个函数。
useEffect()的作用就是指定一个副效应函数,组件每渲染一次,该函数就自动执行一次。组件首次在网页 DOM 加载后,副效应函数也会执行

当然useEffect也有第二个参数,第二个参数是UseEffect的依赖项。

有时候,我们不希望useEffect()每次渲染都执行,这时可以使用它的第二个参数,使用一个数组指定副效应函数的依赖项,只有依赖项发生变化,才会重新渲染。

function Welcome(props) {
  useEffect(() => {
    document.title = `Hello, ${props.name}`;
  }, [props.name]);
  return <h1>Hello, {props.name}</h1>;
}

上面例子中,useEffect()的第二个参数是一个数组,指定了第一个参数(副效应函数)的依赖项(props.name)。只有该变量发生变化时,副效应函数才会执行。

如果第二个参数是一个空数组,就表明副效应参数没有任何依赖项。因此,副效应函数这时只会在组件加载进入 DOM 后执行一次,后面组件重新渲染,就不会再次执行。这很合理,由于副效应不依赖任何变量,所以那些变量无论怎么变,副效应函数的执行结果都不会改变,所以运行一次就够了。

只要是副效应,都可以使用useEffect()引入。它的常见用途有下面几种。

  1. 获取数据(data fetching)
  2. 事件监听或订阅(setting up a subscription)
  3. 改变DOM(changing the DOM)
  4. 输出日志(logging)

注意:使用useEffect()时,有一点需要注意。如果有多个副效应,应该调用多个useEffect(),而不应该合并写在一起。


http://www.niftyadmin.cn/n/1029869.html

相关文章

EAUML日拱一卒-0基础学习微信小程序(15)-弄得像真的一样

光显示数字当然没什么意思&#xff0c;我们稍加修改&#xff0c;争取把这个小程序弄的像真的一样。 创建/添加图像资源 首先用Word画&#xff0c;然后转换成png。 接下来在小程序工程中添加images目录&#xff0c;将png文件拷贝到该目录中。 index.wxml <!--index.wxml-->…

列的分拆显示

create table ta(id int, name varchar(50))insert taselect 1, aa,bbunion all select 2, aaa,bbb,cccunion all select 3, Aa,Bb,Cc,Dd 方法1通过游标实现: declare tb table(id int, name varchar(50))--用表变量显示效果DECLARE id int,name…

NET 2.0的Provider模式

[原文&#xff1a;The .NET 2.0 Framework Provider Pattern] [中文名&#xff1a;.NET 2.0的Provider模式] [出处&#xff1a;http://www.c-sharpcorner.com/] [作者&#xff1a;Matthew Cochran] [翻译&#xff1a;极地银狐.NET] 第一部分: Provider模式统览 Provider设计模式…

EAUML日拱一卒-0基础学习微信小程序(16)-使用移动平均消除抖动

增加了表盘的图形显示以后&#xff0c;这个小程序看起来是那么回事了。但是还有一个小毛病&#xff0c;数字也好&#xff0c;表盘的旋转速度&#xff0c;都不是很均匀。今天就来解决这个问题。 简单移动平均法 移动平均的计算公式如下&#xff1a; Ft(At-1At-2At-3…At-n)/n&am…

antd中的message.loading

antd中的message.loading 今儿遇到一个需求问题&#xff0c;在table中的操作栏点击删除&#xff0c;由于是向后端发起请求&#xff0c;所以需要一个loading效果&#xff0c;loading又是使用的antd中的message.loading&#xff08;&#xff09;。 如下是antd中提供的写法 imp…

EAUML日拱一卒-0基础学习微信小程序(17)-学到什么程度算行?

每当学习一种新技术的时候都会遇到这个问题&#xff1a;学到什么程度算行&#xff1f; 以下纯粹是作者个人见解&#xff0c;就当抛砖引玉吧。 一句话&#xff1a;学到可以独立开发即可。 是不是还是不好操作&#xff1f;那就用两句话来表述&#xff1a; 面对一个需求&#xff0…

CSS隐藏元素的几大方法

CSS隐藏元素的几大方法 display&#xff1a;none&#xff1b; 使用none值会让元素从文档中直接删除&#xff0c;”直接消失不见了”&#xff0c;但是设置为display为none的元素还是会留在DOM树中&#xff0c;只是没有在渲染树中&#xff1b; visibility&#xff1a;hidden&…

EAUML日拱一卒-微信小程序实战:位置闹铃 (1)-功能介绍

不知道你有没有这样的经验&#xff0c;经常会想着到了哪里哪里做什么事。例如&#xff1a; 到了小区门口买牛奶 到家了打个电话 。。。 但是真到了那个地方&#xff0c;却错过了。我们就以解决这个问题为目标&#xff0c;开发一个微信小程序&#xff1a;位置闹铃。 功能概要…