常见React Hooks 钩子函数用法

news2024/11/26 3:41:13

一、useState

useState()用于为函数组件引入状态(state)。纯函数不能有状态,所以把状态放在钩子里面。

import React, { useState } from 'react'
import './Button.css'

export function UseStateWithoutFunc() {
  const [name, setName] = useState('何遇')
  const [age, setAge] = useState()

  function onChange() {
    setName('张三') // 修改name
    setAge(23) // 修改age
  }

  return (
    <>
      <div className={'nameButton'}>姓名: {name}</div>
      <div className={'ageButton'}>年龄: {age === undefined ? '未知' : age}</div>
      <button onClick={onChange}>click</button>
    </>
  )
}

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

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

当没有赋予初始值的时候,这个变量则是undefined,没有定义的。当再次执行set函数的时候,则会被赋值。如上述年龄字段age,一开始是undefined的,所以显示出来的效果就是“未知”。

当点击button的时候,触发onChange函数,同时给年龄和姓名赋新值。因此点击按钮之后显示效果如下:

二、useEffect

seEffect()用来引入具有副作用的操作,最常见的就是向服务器请求数据。以前,放在componentDidMount里面的代码,现在可以放在useEffect()。

useEffect()的用法如下:

useEffect(() => {
  // Async Action
}, [dependencies]); 

上面用法中,useEffect()接受两个参数。

  • 第一个参数是一个函数,异步操作的代码放在里面。
  • 第二个参数是一个数组,用于给出 Effect 的依赖项,只要这个数组发生变化,useEffect()就会执行。第二个参数可以省略,这时每次组件渲染时,就会执行useEffect()。

下面是Person.js和Person.css代码

import {useEffect, useState} from "react";
import "./Person.css";

const Person = ({personId}) => {
  const[loading, setLoading] = useState(true);
  const[person, setPerson] = useState({});

  useEffect(() => {
    setLoading(true);
    fetch(`https://swapi.dev/api/people/${personId}`)
      .then(response => response.json())
      .then(data => {
        setLoading(false)
        setPerson(data)
      });
  }, [personId]);


  if (loading) {
    return <p>Loading...</p>
  }
  return <div>
    <p>You're viewing: {person.name}</p>
    <p>Height: {person.height}</p>
  <p>Mass: {person.mass}</p>
  </div>
}

export default function PersonComponent() {
  const [show, setShow] = useState("1");

  return (
      <div className="App">
      <Person personId={show}></Person>
      <div>
      Show:
    <button onClick={() => setShow("3")}>R2-D2</button>
      <button onClick={() => setShow("2")}>C-3PO</button>
    </div>
    </div>
  )
}
* {
  margin: 0;
  padding: 0;
}
body {
  padding: 10px;
  background-color: #f5f5fa;
  color: #222;
}
h2 {
  margin-bottom: 20px;
  font-family: 'Helvetica';
  font-weight: 400;
}
.App {
  font-family: 'Helvetica';
  font-weight: 200;
  text-align: left;
  width: 400px;
}
input {
  border: 1px solid #ddd;
  background-color: #fff;
  padding: 5px 10px;
  margin: 10px 0;
  border-radius: 5px;
  width: 300px;
}
button {
  padding: 5px 20px;
  background: #0066cc;
  border: 1px solid #fff;
  border-radius: 15px;
  color: #fff;
  margin-top: 10px;
  margin-bottom: 10px;
}
button:hover {
  cursor: pointer;
  box-shadow: 0px 2px 4px #0044aa40;
}
button:active {
  background: #0044aa;
}
button:focus {outline:0;}
ul {
  margin-left: 20px;
}

.navbar {
  display: flex;
  flex-direction: row;
  justify-content: space-between;
  padding-bottom: 10px;
  margin-bottom: 20px;
  border-bottom: 1px solid #ccc;
}
.messages h1 {
  margin-bottom: 20px;
}
.messages p {
  margin-bottom: 10px;
}
.message {
  background-color: #fff;
  border: 1px solid #ddd;
  padding: 10px;
  border-radius: 4px;
}

在请求https://swapi.dev/api/people/{personId}/ 这个接口,每次传入不同的personId值,就可以请求到不同人的数据。

每次personId发生改变之后,Person组件里的useEffect里的方法就会执行一次也就是会去请求一次后端数据,请求到了之后再刷新界面。没有请求到的时候由于loading默认设为true,因此就会执行return <p>Loading...</p>这段代码,就会展示Loading的文字。等请求到之后,会执行这行 setLoading(false),将loading字段设为false,因此此时就不会展示Loading的文字,而是展示姓名、身高等字样。

点击R2-D2数据还没请求到的时候,会显示Loading

请求到对应的数据之后,就会展示对应的个人信息

三、useReducer

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;
  }
}

组件代码如下。

export default function UseReducerComponent() {
  const[state, dispatch] = useReducer(myReducer, {count: 0})

  return (
    <div className="App">
    <button onClick={() => dispatch({type: 'countUp'})}>
    +1
    </button>
    <p>Count: {state.count}</p>
    </div>
  )
}

import {useReducer} from "react";
import "./styles.css";


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

export default function UseReducerComponent() {
    const[state, dispatch] = useReducer(myReducer, {count: 0})

    return (
        <div className="App">
            <button onClick={() => dispatch({type: 'countUp'})}>
                +1
            </button>
            <p>Count: {state.count}</p>
        </div>
    )
}

styles.css样式如下:

* {
  margin: 0;
  padding: 0;
}
body {
  padding: 10px;
  background-color: #f5f5fa;
  color: #222;
}
h2 {
  margin-bottom: 20px;
  font-family: 'Helvetica';
  font-weight: 400;
}
.App {
  font-family: 'Helvetica';
  font-weight: 200;
  text-align: left;
  width: 400px;
}
input {
  border: 1px solid #ddd;
  background-color: #fff;
  padding: 5px 10px;
  margin: 10px 0;
  border-radius: 5px;
  width: 300px;
}
button {
  padding: 5px 20px;
  background: #0066cc;
  border: 1px solid #fff;
  border-radius: 15px;
  color: #fff;
  margin-top: 10px;
  margin-bottom: 10px;
}
button:hover {
  cursor: pointer;
  box-shadow: 0px 2px 4px #0044aa40;
}
button:active {
  background: #0044aa;
}
button:focus {outline:0;}
ul {
  margin-left: 20px;
}

.navbar {
  display: flex;
  flex-direction: row;
  justify-content: space-between;
  padding-bottom: 10px;
  margin-bottom: 20px;
  border-bottom: 1px solid #ccc;
}
.messages h1 {
  margin-bottom: 20px;
}
.messages p {
  margin-bottom: 10px;
}
.message {
  background-color: #fff;
  border: 1px solid #ddd;
  padding: 10px;
  border-radius: 4px;
}

四、useContext

如果需要在组件之间共享状态,可以使用useContext()。

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

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

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

const AppContext = React.createContext({});

组件封装代码如下。

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

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

Navbar 组件的代码如下。下面代码中,useContext()钩子函数用来引入 Context 对象,从中获取username属性

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

Message 组件的代码如下。下面代码中,useContext()钩子函数用来引入 Context 对象,从中获取username属性

const Messages = () => {
  const { username } = useContext(AppContext)

  return (
    <div className="messages">
      <h1>Messages</h1>
      <p>1 message for {username}</p>
      <p className="message">useContext is awesome!</p>
    </div>
  )
}

UseContextComponent.js代码如下所示:

import React, { useContext } from "react";
import "./style.css";

const AppContext = React.createContext({});

const Navbar = () => {
    const { username } = useContext(AppContext)

    return (
        <div className="navbar">
            <p>AwesomeSite</p>
            <p>{username}</p>
        </div>
    )
}

const Messages = () => {
    const { username } = useContext(AppContext)

    return (
        <div className="messages">
            <h1>Messages</h1>
            <p>1 message for {username}</p>
            <p className="message">useContext is awesome!</p>
        </div>
    )
}

export default function UseContextComponent() {
    return (
        <AppContext.Provider value={{
            username: 'superawesome'
        }}>
            <div className="App">
                <Navbar />
                <Messages />
            </div>
        </AppContext.Provider>
    );
}

style.css文件如下:

* {
    margin: 0;
    padding: 0;
}
body {
    padding: 10px;
    background-color: #f5f5fa;
    color: #222;
}
h2 {
    margin-bottom: 20px;
    font-family: 'Helvetica';
    font-weight: 400;
}
.App {
    font-family: 'Helvetica';
    font-weight: 200;
    text-align: left;
    width: 400px;
}
input {
    border: 1px solid #ddd;
    background-color: #fff;
    padding: 5px 10px;
    margin: 10px 0;
    border-radius: 5px;
    width: 300px;
}
button {
    padding: 5px 20px;
    background: #0066cc;
    border: 1px solid #fff;
    border-radius: 15px;
    color: #fff;
    margin-top: 10px;
    margin-bottom: 10px;
}
button:hover {
    cursor: pointer;
    box-shadow: 0px 2px 4px #0044aa40;
}
button:active {
    background: #0044aa;
}
button:focus {outline:0;}
ul {
    margin-left: 20px;
}

.navbar {
    display: flex;
    flex-direction: row;
    justify-content: space-between;
    padding-bottom: 10px;
    margin-bottom: 20px;
    border-bottom: 1px solid #ccc;
}
.messages h1 {
    margin-bottom: 20px;
}
.messages p {
    margin-bottom: 10px;
}
.message {
    background-color: #fff;
    border: 1px solid #ddd;
    padding: 10px;
    border-radius: 4px;
}

可以理解为一种共享上下文状态。类似于Android里context的一样,获取上下文信息的。

第一块是组件Navbar展示的

第二块是组件Message展示的

引用文献:

【1】轻松学会 React 钩子:以 useEffect() 为例 - 阮一峰的网络日志

【2】React Hooks 入门教程 - 阮一峰的网络日志

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1182852.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

RK3588平台开发系列讲解(显示篇)MIPI 屏幕驱动调试

🚀返回专栏总目录 文章目录 一、背光驱动1.1、背光 PWM 节点设置1.2、backlight 节点设置二、屏幕初始化序列发送时序参数设置2.1、设备树下 DSI 节点编写2.2、DSI 的 panel 子节点编写沉淀、分享、成长,让自己和他人都能有所收获!😄 📢 调试 MIPI 屏幕主要有三部分内容…

Qt Creator插件

这里以Qt Creator 4.15.2版本的源码为示例进行分析 源码结构如下&#xff0c;为了追溯其插件加载过程&#xff0c;从main.cpp入手 Qt Creator的插件目录&#xff0c;生成的插件&#xff0c;好几十个呢 Qt Creator插件的读取 int main(int argc, char **argv)中以下代码创建插…

jenkins Java heap space

jenkins Java heap space&#xff0c;是内存不够。 两个解决方案&#xff1a; 一&#xff0c;修改配置文件 windows系统中&#xff0c;找到Jenkins的安装路径&#xff0c; 修改jenkins.xml 将 -Xmx256m 改为 -Xmx1024m 或者更大 重启jenkins服务。 二&#xff0c;jenkins增…

海思SD3403/SS928开发板 开发记录二: 设置网络 telnet连接开发板

1.设置网络 设置桥接网络 并修改虚拟机IP网段 问题1.参照前一篇博客 2.ping 测试 主机 虚拟机 板端 相互通信 3.telnet 登录板端

Ps:自由变换

自由变换 Free Transform是 Photoshop 中最常用的命令之一&#xff0c;可对图层、图层蒙版、选区、选区内容等进行缩放、旋转、斜切、扭曲、透视等各种变换操作。 Ps菜单&#xff1a;编辑/自由变换 Edit/Free Transform 快捷键&#xff1a;Ctrl T 或者&#xff0c;在图层上右键…

【全志H616 使用标准库 完成自制串口库(分文件实现) orangepi zero2(开源)】.md updata: 23/11/07

文章目录 H616 把玩注意&#xff1a;Linux内核版本5.16 及以上&#xff0c;需手动配置i2c-3 uart5驱动配置示例 分文件编译时需将每个文件一同编译 &#xff08;空格隔开&#xff09;例&#xff1a; ggc a.c b.c b.h -lpthread -lxxx..; 常用命令查看驱动文件查看内核检测信息/…

2000-2022年上市公司专利申请、创新绩效数据

2000-2022年上市公司专利申请、创新绩效数据 1、时间&#xff1a;2000-2022年 2、指标&#xff1a;年份、股票代码、股票简称、行业名称、行业代码、省份、城市、区县、行政区划代码、城市代码、区县代码、首次上市年份、上市状态、专利申请总量、发明专利申请总量、实用新型…

技术分享 | 使用 cURL 发送请求

cURL 是一个通过 URL 传输数据的&#xff0c;功能强大的命令行工具。cURL 可以与 Chrome Devtool 工具配合使用&#xff0c;把浏览器发送的真实请求还原出来&#xff0c;附带认证信息&#xff0c;脱离浏览器执行&#xff0c;方便开发者重放请求、修改参数调试&#xff0c;编写脚…

OJ项目——使用JWT生成Token

目录 前言 1、项目中需要修改哪些东西&#xff1f; 1.1、引入依赖 1.2、编写JWT工具类 1.3、登陆成功后&#xff0c;把以前的session修改为token 1.4、登录拦截器的修改 1.5、展示前端部分代码 前言 有兴趣的小伙伴&#xff0c;可以先看看这篇文章&#xff0c;如果使用s…

python 之 集合的相关知识

文章目录 1. 创建集合使用花括号 {}使用 set() 函数 2. 集合的特点3. 集合操作添加元素删除元素 4. 集合运算5. 不可变集合总结 在 Python 中&#xff0c;集合&#xff08;Set&#xff09;是一种无序且不重复的数据集合。它是由一组唯一元素组成的。下面是关于集合的一些基本知…

6.判断是不是闰年

#include<stdio.h>void fun(int year){if(year%40&&year%100!0||year%4000)printf("%d 是闰年\n",year);elseprintf("%d 不是闰年\n",year);}int main(){int year;scanf("%d",&year);fun(year);return 0;}

java记一次replace替换中文双引号失败的问题

事情的起因是一个Java项目中要调用第三方接口&#xff0c;而且无法远程访问该接口进行调试&#xff0c;只能本地写完功能后现场部署测试。 其中接口文档是这样描述的&#xff1a; 实际第三方接口返回值是带中文双引号的字符串【“1”】或者带有英文双引号的字符串【"1&qu…

Python武器库开发-常用模块之subprocess模块(十九)

常用模块之subprocess模块(十九) subprocess模块介绍 subprocess 模块允许我们启动一个新进程&#xff0c;并连接到它们的输入/输出/错误管道&#xff0c;从而获取返回值。subprocess 它可以用来调用第三方工具&#xff08;例如&#xff1a;exe、另一个python文件、命令行工具…

Bun 1.0.7 版本发布,实现多个 Node.js 兼容改进

导读Bun 是一个集打包工具、转译器和包管理器于一体的 JavaScript 运行时&#xff0c;由 Jarred Sumner 发布了 1.0.7 版本。本次更新实现了对 Node.js 运行时的多项兼容性改进&#xff0c;并修复了近 60 个 bug。 根据发布说明&#xff0c;本版本对 “bun install” 命令进行…

yolov8+多算法多目标追踪+实例分割+目标检测+姿态估计(代码+教程)

多目标追踪实例分割目标检测 YOLO (You Only Look Once) 是一个流行的目标检测算法&#xff0c;它能够在图像中准确地定位和识别多个物体。 本项目是基于 YOLO 算法的目标跟踪系统&#xff0c;它将 YOLO 的目标检测功能与目标跟踪技术相结合&#xff0c;实现了实时的多目标跟…

Linux笔记——Ubuntu子系统从系统盘迁移到非系统盘

Linux笔记——Ubuntu子系统从系统盘迁移到非系统盘 一、子系统迁移1. 关闭linux子系统2. 使用move-wsl进行迁移 二、 虚拟机子系统瘦身 安了子系统还没用几天&#xff0c;C盘提示我没空间了。。。剩余0kb的那种。。。Ubuntu安装的时候默认按C盘了&#xff0c;所以还是移走腾点地…

【神经网络】【GoogleNet】

1、引言 卷积神经网络是当前最热门的技术&#xff0c;我想深入地学习这门技术&#xff0c;从他的发展历史开始&#xff0c;了解神经网络算法的兴衰起伏&#xff1b;同时了解他在发展过程中的**里程碑式算法**&#xff0c;能更好的把握神经网络发展的未来趋势&#xff0c;了解神…

第1天:Python基础语法(一)

** 1、Python简介 ** Python是一种高级、通用的编程语言&#xff0c;由Guido van Rossum于1989年创造。它被设计为易于阅读和理解&#xff0c;具有简洁而清晰的语法&#xff0c;使得初学者和专业开发人员都能够轻松上手。 Python拥有丰富的标准库&#xff0c;提供了广泛的功…

生态环境领域基于R语言piecewiseSEM结构方程模型

结构方程模型&#xff08;Sructural Equation Modeling&#xff0c;SEM&#xff09;可分析系统内变量间的相互关系&#xff0c;并通过图形化方式清晰展示系统中多变量因果关系网&#xff0c;具有强大的数据分析功能和广泛的适用性&#xff0c;是近年来生态、进化、环境、地学、…

AI 绘画 | Stable Diffusion 涂鸦功能与局部重绘

在 StableDiffusion图生图的面板里&#xff0c;除了图生图&#xff08;img2img&#xff09;选卡外&#xff0c;还有局部重绘(Inpaint)&#xff0c;涂鸦(Sketch)&#xff0c;涂鸦重绘(Inpaint Sketch),上传重绘蒙版&#xff08;Inpaint Uplaod&#xff09;、批量处理&#xff08…