react焕发第二春,函数式编程HOOKS

2024-03-02 15:20

本文主要是介绍react焕发第二春,函数式编程HOOKS,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

文章目录

    • HOOKS
    • Hook 使用规则
    • useState():状态钩子
    • useEffect():副作用钩子
      • 副效应是什么?
      • useEffect() 的用法
      • useEffect() 的用途
    • useContext():共享状态钩子
    • useReducer():action 钩子
    • 创建自己的 Hooks
    • Hook API

HOOKS

Hook 是 React 16.8 的新增特性。它可以让你在不编写 class 的情况下使用 state 以及其他的 React 特性

Hook 是一些可以让你在函数组件里“钩入” React state 及生命周期等特性的函数

Hook 这个单词的意思是"钩子"。

React Hooks 的意思是,组件尽量写成纯函数,如果需要外部功能和副作用,就用钩子把外部代码"钩"进来。 React Hooks 就是那些钩子。

你需要什么功能,就使用什么钩子。React 默认提供了一些常用钩子,你也可以封装自己的钩子。

所有的钩子都是为函数引入外部功能,所以 React 约定,钩子一律使用use前缀命名,便于识别。你要使用 xxx 功能,钩子就命名为 usexxx。

Hook 使用规则

Hook 就是 JavaScript 函数,但是使用它们会有两个额外的规则:

  • 只能在函数最外层调用 Hook。不要在循环、条件判断或者子函数中调用。
  • 只能在 React 的函数组件和自定义hook中调用 Hook。不要在其他 JavaScript 函数中调用。

useState():状态钩子

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

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

import React, { useState } from "react"function Example() {// 声明一个新的叫做 “count” 的 state 变量const [count, setCount] = useState(0);// 声明多个 state 变量!const [age, setAge] = useState(42);const [fruit, setFruit] = useState('banana');const [todos, setTodos] = useState([{ text: 'Learn Hooks' }]);return (<div><p>You clicked {count} times</p><button onClick={() => setCount(count + 1)}>Click me</button></div>);
}
  • 调用 useState 方法的时候做了什么? 它定义一个 “state 变量”
  • useState 需要哪些参数? useState() 方法里面唯一的参数就是初始 state
  • useState 方法的返回值是什么? 返回值为:当前 state 以及更新 state 的函数

useEffect():副作用钩子

function Welcome(props) {return <h1>Hello, {props.name}</h1>;
}

这个函数只做一件事,就是根据输入的参数,返回组件的 HTML 代码。这种只进行单纯的数据计算(换算)的函数,在函数式编程里面称为 “纯函数”(pure function)。

副效应是什么?

看到这里,你可能会产生一个疑问:如果纯函数只能进行数据计算,那些不涉及计算的操作(比如生成日志、储存数据、改变应用状态等等)应该写在哪里呢?

函数式编程将那些跟数据计算无关的操作,都称为 “副效应” (side effect) 。如果函数内部直接包含产生副效应的操作,就不再是纯函数了,我们称之为不纯的函数。

纯函数内部只有通过间接的手段(即通过其他函数调用),才能包含副效应。

useEffect() 的用法

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

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

useEffect()的作用就是指定一个副效应函数,组件每渲染一次,该函数就自动执行一次。组件首次在网页 DOM 加载后,副效应函数也会执行。

React 组件中数据获取、订阅或者手动修改过 DOM。我们统一把这些操作称为“副作用”,或者简称为“作用”。

useEffect 就是一个 Effect Hook,给函数组件增加了操作副作用的能力。它跟 class 组件中的 componentDidMountcomponentDidUpdatecomponentWillUnmount 具有相同的用途,只不过被合并成了一个 API

import React, { useState, useEffect } from 'react';const Person = ({ personId }) => {const [loading, setLoading] = useState(true);const [person, setPerson] = useState({});useEffect(() => {setLoading(true); fetch(`https://swapi.co/api/people/${personId}/`).then(response => response.json()).then(data => {setPerson(data);setLoading(false);});}, [personId])if (loading === true) {return <p>Loading ...</p>}return <div><p>You're viewing: {person.name}</p><p>Height: {person.height}</p><p>Mass: {person.mass}</p></div>
}

由于副作用函数是在组件内声明的,所以它们可以访问到组件的 props 和 state

  • useEffect 做了什么? 通过使用这个 Hook,你可以告诉 React 组件需要在渲染后执行某些操作
  • 为什么在组件内部调用 useEffectuseEffect 放在组件内部让我们可以在 effect 中直接访问 count state 变量(或其他 props)
  • useEffect 会在每次渲染后都执行吗? 是的,默认情况下,它在第一次渲染之后每次更新之后都会执行
  • 为什么要在 effect 中返回一个函数? 这是 effect 可选的清除机制。每个 effect 都可以返回一个清除函数
  • React 何时清除 effect? React 会在组件卸载的时候执行清除操作
  • useEffect()允许返回一个函数,在组件卸载时,执行该函数,清理副效应。如果不需要清理副效应,useEffect()就不用返回任何值。
  • 使用useEffect()时,有一点需要注意。如果有多个副效应,应该调用多个useEffect(),而不应该合并写在一起。
function App() {const [varA, setVarA] = useState(0);const [varB, setVarB] = useState(0);useEffect(() => {const timeout = setTimeout(() => setVarA(varA + 1), 1000);return () => clearTimeout(timeout);}, [varA]);useEffect(() => {const timeout = setTimeout(() => setVarB(varB + 2), 2000);return () => clearTimeout(timeout);}, [varB]);return <span>{varA}, {varB}</span>;
}

useEffect() 的用途

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

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

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 组件的代码如下。

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

上面代码中,useContext()钩子函数用来引入 Context 对象,从中获取username属性。

Message 组件的代码也类似。

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

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

创建自己的 Hooks

上例的 Hooks 代码还可以封装起来,变成一个自定义的 Hook,便于共享。

const usePerson = (personId) => {
const [loading, setLoading] = useState(true);
const [person, setPerson] = useState({});
useEffect(() => {setLoading(true);fetch(`https://swapi.co/api/people/${personId}/`).then(response => response.json()).then(data => {setPerson(data);setLoading(false);});}, [personId]);  return [loading, person];};

上面代码中,usePerson()就是一个自定义的 Hook。

Person 组件就改用这个新的钩子,引入封装的逻辑。

 const Person = ({ personId }) => {const [loading, person] = usePerson(personId);if (loading === true) {return <p>Loading ...</p>;
}return (<div><p>You're viewing: {person.name}</p><p>Height: {person.height}</p><p>Mass: {person.mass}</p></div>);
};

Hook API

在这里插入图片描述

这篇关于react焕发第二春,函数式编程HOOKS的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/766564

相关文章

Python的time模块一些常用功能(各种与时间相关的函数)

《Python的time模块一些常用功能(各种与时间相关的函数)》Python的time模块提供了各种与时间相关的函数,包括获取当前时间、处理时间间隔、执行时间测量等,:本文主要介绍Python的... 目录1. 获取当前时间2. 时间格式化3. 延时执行4. 时间戳运算5. 计算代码执行时间6. 转换为指

Python正则表达式语法及re模块中的常用函数详解

《Python正则表达式语法及re模块中的常用函数详解》这篇文章主要给大家介绍了关于Python正则表达式语法及re模块中常用函数的相关资料,正则表达式是一种强大的字符串处理工具,可以用于匹配、切分、... 目录概念、作用和步骤语法re模块中的常用函数总结 概念、作用和步骤概念: 本身也是一个字符串,其中

HTML5中的Microdata与历史记录管理详解

《HTML5中的Microdata与历史记录管理详解》Microdata作为HTML5新增的一个特性,它允许开发者在HTML文档中添加更多的语义信息,以便于搜索引擎和浏览器更好地理解页面内容,本文将探... 目录html5中的Mijscrodata与历史记录管理背景简介html5中的Microdata使用M

html5的响应式布局的方法示例详解

《html5的响应式布局的方法示例详解》:本文主要介绍了HTML5中使用媒体查询和Flexbox进行响应式布局的方法,简要介绍了CSSGrid布局的基础知识和如何实现自动换行的网格布局,详细内容请阅读本文,希望能对你有所帮助... 一 使用媒体查询响应式布局        使用的参数@media这是常用的

HTML5表格语法格式详解

《HTML5表格语法格式详解》在HTML语法中,表格主要通过table、tr和td3个标签构成,本文通过实例代码讲解HTML5表格语法格式,感兴趣的朋友一起看看吧... 目录一、表格1.表格语法格式2.表格属性 3.例子二、不规则表格1.跨行2.跨列3.例子一、表格在html语法中,表格主要通过< tab

Vue3组件中getCurrentInstance()获取App实例,但是返回null的解决方案

《Vue3组件中getCurrentInstance()获取App实例,但是返回null的解决方案》:本文主要介绍Vue3组件中getCurrentInstance()获取App实例,但是返回nu... 目录vue3组件中getCurrentInstajavascriptnce()获取App实例,但是返回n

JS+HTML实现在线图片水印添加工具

《JS+HTML实现在线图片水印添加工具》在社交媒体和内容创作日益频繁的今天,如何保护原创内容、展示品牌身份成了一个不得不面对的问题,本文将实现一个完全基于HTML+CSS构建的现代化图片水印在线工具... 目录概述功能亮点使用方法技术解析延伸思考运行效果项目源码下载总结概述在社交媒体和内容创作日益频繁的

前端CSS Grid 布局示例详解

《前端CSSGrid布局示例详解》CSSGrid是一种二维布局系统,可以同时控制行和列,相比Flex(一维布局),更适合用在整体页面布局或复杂模块结构中,:本文主要介绍前端CSSGri... 目录css Grid 布局详解(通俗易懂版)一、概述二、基础概念三、创建 Grid 容器四、定义网格行和列五、设置行

shell编程之函数与数组的使用详解

《shell编程之函数与数组的使用详解》:本文主要介绍shell编程之函数与数组的使用,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录shell函数函数的用法俩个数求和系统资源监控并报警函数函数变量的作用范围函数的参数递归函数shell数组获取数组的长度读取某下的

前端下载文件时如何后端返回的文件流一些常见方法

《前端下载文件时如何后端返回的文件流一些常见方法》:本文主要介绍前端下载文件时如何后端返回的文件流一些常见方法,包括使用Blob和URL.createObjectURL创建下载链接,以及处理带有C... 目录1. 使用 Blob 和 URL.createObjectURL 创建下载链接例子:使用 Blob