文章目录

  • 为什么会有Hooks?
  • 什么是Hooks?
    • 一、userState():状态钩子
    • 二、useEffect():副作用钩子
    • 三、useContext():共享状态钩子
    • 四、useReducer():Action钩子
    • 五、创建自己的Hooks

为什么会有Hooks?

首先要说一下React的组件创建方式,一种是类组件,一种是纯函数组件,并且React团队希望,组件不要变成复杂的容器,最好只是数据流的管道。开发者根据需要,组合管道即可。也就是说组件的最佳写法应该是函数,而不是类。

但是我们知道,在以往开发中类组件和纯函数组件的区别是很大的,纯函数组件有着类组件不具备的多种特点,简单列举几条

  • 纯函数组件没有状态
  • 纯函数组件没有生命周期
  • 纯函数组件没有this
  • 只能是纯函数

这就注定,我们所推崇的函数组件,只能做UI展示的功能,涉及到状态的管理与切换,我们不得不用类组件或者redux。React团队设计了React Hooks,就是加强版的函数组件,我们可以完全不使用 class,就能写出一个全功能的组件。

什么是Hooks?

'Hooks’的单词意思为“钩子”
React为我们提供了一些常用的钩子,当然有特殊需要,我们也可以写自己的钩子。下面是React为我们提供的默认的四种最常用钩子:

  • useState()
  • userContext()
  • userReducer()
  • useEffect()

React约定,钩子一律使用 use前缀命名。所以,你自己定义的钩子都要命名为useXXX。

一、userState():状态钩子

我们知道,纯函数组件没有状态,useState()用于为函数组件引入状态。

实现累加的示例:

import React, {useState} from 'react'
const AddCount = () => {const [ count, setCount ] = useState(0)const addcount = () => {let newCount = countsetCount(newCount+=1)} return (<><p>{count}</p><button onClick={addcount}>count++</button></>)
}
export default AddCount

通过上面的代码,我们实现了一个功能完全一样的计数器,代码看起来更加的轻便简洁,没有了继承,没有了渲染逻辑,没有了生命周期等。这就是hooks存在的意义。

在useState()中,它接受状态的初始值作为参数,即上例中计数的初始值,它返回一个数组,其中数组第一项为一个变量,指向状态的当前值。类似this.state,第二项是一个函数,用来更新状态,类似setState。该函数的命名,我们约定为set前缀加状态的变量名。

二、useEffect():副作用钩子

useEffect(() => {},[array])

useEffect()接受两个参数,

  • 第一个参数是函数,第二个参数是一个数组,用来给出Effect的依赖项。只要这个数组发生变化,useEffect()就会执行。这是监听数据变化。
  • 当第二项省略不填时,useEffect()会在每次组件渲染时执行。这一点类似于类组件的componentDidMount,初始化渲染。

下面的示例,有第二个参数,useEffect()依赖第二项数组变化而调用

import React, { useState, useEffect } from 'react'const AsyncPage = ({name}) => {const [loading, setLoading] = useState(true)
const [person, setPerson] = useState({})useEffect(() => {setLoading(true)setTimeout(()=> {setLoading(false)setPerson({name})},2000)},[name])return (<>{loading?<p>Loading...</p>:<p>{person.name}</p>}</>)
}const PersonPage = () =>{const [state, setState] = useState('')const changeName = (name) => {setState(name)}return (<><AsyncPage name={state}/><button onClick={() => {changeName('名字1')}}>名字1</button><button onClick={() => {changeName('名字2')}}>名字2</button></>)
}export default PersonPage 

下面的示例,无第二个参数,只是挂载时调用

import React, { useState, useEffect } from 'react'
const AsyncPage = () => {const [loading, setLoading] = useState(true)useEffect(() => {      // 没有第二个参数,则只是挂载时调用setTimeout(()=> {setLoading(false)},5000)})return (loading ? <p>Loading...</p>: <p>异步请求完成</p>)
}export default AsyncPage

上面代码中,通过改变传给AsyncPage的props,从而调用useEffect()

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

该钩子的作用是,在组件之间共享状态。其作用就是可以做状态的分发,在React16.X以后支持,避免了react逐层通过Props传递数据

下面是一个例子,现在假设有A组件和B组件需要共享一个状态。

import React,{ useContext } from 'react'
const Ceshi = () => {const AppContext = React.createContext({})//A组件const A =() => {const { name } = useContext(AppContext)return (<p>我是A组件的名字{name}<span>我是A的子组件{name}</span></p>)}//B组件const B =() => {const { name } = useContext(AppContext)return (<p>我是B组件的名字{name}</p>)}return (<AppContext.Provider value={{name: 'hook测试'}}><A/><B/></AppContext.Provider>)
}
export default Ceshi

可以看到,我们可以通过hooks做状态的共享。

四、useReducer():Action钩子

我们知道,在使用React的过程中,如遇到状态管理,我们一般会用到Redux,而React本身是不提供状态管理的。而useReducer()为我们提供了状态管理。

首先,关于redux我们都知道,其原理是我们通过用户在页面中发起action,从而通过reducer方法来改变state,从而实现页面和状态的通信

而Reducer的形式是(state, action) => newstate。类似,我们的useReducer()是这样的

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

接受reducer函数和状态的初始值作为参数
返回一个数组,其中第一项为当前的状态值,第二项为发送action的dispatch函数。下面我们依然用来实现一个计数器。

和redux一样,我们是需要通过页面组件发起action来调用reducer方法,从而改变状态,达到改变页面UI的这样一个过程。所以我们会先写一个Reducer函数,然后通过useReducer()返回给我们的state和dispatch来驱动这个数据流。思路就是这样,下面我们上代码

import React,{useReducer} from 'react'const AddCount = () => {//创建一个reducerconst reducer = (state, action) =>  {if(action.type === ''add){return {...state,count: state.count +1,}}else {return state}}const addcount = () => { dispatch({               //触发reducer中相应的操作type: 'add'})}//创建一个reducerconst [state, dispatch] = useReducer(reducer, {count: 0})return (<div><p>{state.count}</p><button onClick={addcount}>count++</button></div>)
}
export default AddCount

通过代码我们看到了,我们使用useReducer()代替了Redux的功能,但useReducer无法为我们提供中间件等功能,假如你有这些需求,还是需要用到redux

五、创建自己的Hooks

React提供给我们的默认React Hooks,有时候我们需要创建我们自己想要的Hooks,来满足更便捷的开发,在小编看来,无非就是根据业务场景对以上四种Hooks进行组装,从而得到满足自己需求的钩子。
比如,我们要将我们上面的代码功能封装成Hooks:

import React, { useState, useEffect } from 'react'//自定义hooksconst usePerson = (name) => {const [loading, setLoading] = useState(true)const [person, setPerson] = useState({})useEffect(() => {setLoading(true)setTimeout(()=> {setLoading(false)setPerson({name})},2000)},[name])return [loading,person]}//函数组件使用自定义的hooks
const AsyncPage = ({name}) => {const [loading, person] = usePerson(name)return (<>{loading?<p>Loading...</p>:<p>{person.name}</p>}</>)
}//函数组件使用自定义的hooks
const PersonPage = () =>{const [state, setState]=useState('')const changeName = (name) => {setState(name)}return (<><AsyncPage name={state}/><button onClick={() => {changeName('名字1')}}>名字1</button><button onClick={() => {changeName('名字2')}}>名字2</button></>)
}export default PersonPage 

上面代码中,我们将之前的例子封装成了自己的Hooks,便于共享。其中,我们定义usePerson()为我们的自定义Hooks,它接受一个字符串,返回一个数组,数组中包括两个数据的状态,之后我们在使用usePerson()时,会根据我们传入的参数不同而返回不同的状态,然后很简便的应用于我们的页面中。

作者:Nosaj
链接:https://www.jianshu.com/p/d600f749bb19
来源:简书
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

React Hooks 详解相关推荐

  1. React Hooks详解

    文章目录 React Hooks Hooks简介 Hook函数(9种) 自定义Hooks React Hooks Hooks简介 介绍Hooks之前,首先要说一下React的组件创建方式,一种是类组件 ...

  2. React 源码系列 | React Context 详解

    目前来看 Context 是一个非常强大但是很多时候不会直接使用的 api.大多数项目不会直接使用 createContext 然后向下面传递数据,而是采用第三方库(react-redux). 想想项 ...

  3. React.Children 详解

    React.Children 详解 React.Children提供了处理 this.props.children 的 API,this.props.children 支持任何数据(组件.字符串.函数 ...

  4. RN和React路由详解及对比

    前言 在平时H5或者RN开发时,我们业务场景中大部分都不是单页面的需求,那这时我们就能使用路由在进行多页面的切换.下面会对比一下react路由和RN路由的本质区别和使用方法. 路由(routing)是 ...

  5. rn php,RN和React路由详解及对比

    前言 在平时H5或者RN开发时,我们业务场景中大部分都不是单页面的需求,那这时我们就能使用路由在进行多页面的切换.下面会对比一下react路由和RN路由的本质区别和使用方法. 路由(routing)是 ...

  6. Hooks详解(一)

    在React中,创建组件的方式有两种:类式组件和函数式组件.对于刚刚学习react的我(小白)类式组件还是比较容易理解和学习,因为在之前有Vue的学习基础,React的类式组件和Vue的组件可以对比着 ...

  7. 【React】 详解下一代开源混合应用框架Reapp

    详解下一代开源混合应用框架Reapp reapp官网 转载于:https://www.cnblogs.com/dongdong230/p/4314978.html

  8. React中的Hooks详解

    1.概述 React官方网站原文:Hooks 是一项新功能提案,可让您在不编写类的情况下使用 state(状态) 和其他 React 功能. 我总结了下使用Hooks的理由: 1.解决class中的代 ...

  9. react 遍历对象_React 源码系列 | React Children 详解

    本文基于 React V16.8.6,本文代码地址 测试代码 源码讲解 React 中一个元素可能有 0 个.1 个或者多个直接子元素,React 导出的 Children 中包含 5 个处理子元素的 ...

最新文章

  1. oracle12 java_java – 无法使用12c jar创建Eclipse数据源到Oracle 12c.不过11g的作品
  2. 2.7、Android Studio使用翻译编辑器本地化UI
  3. jsp mysql数据修改不了了_通过JSP界面无法修改mysql中的数据
  4. 基于selenium实现12306的登录操作(图形验证码识别)
  5. Eclipse配置Tomcat服务器,通用方法
  6. redis存储的数据类型
  7. javafx窗体程序_JavaFX实际应用程序:AISO HRC-Matic
  8. 学习笔记 04----声明和类
  9. 关于MySQL存储过程异常处理的一点心得
  10. mssql 获取自增列起始及增量
  11. 多媒体计算机中的扬声器指的是音箱和,怎样算合格? 音箱主要指标参数全解析...
  12. java异步编程书籍_《Java异步编程实战》隆重上市!!!
  13. 如何使用PAUP4、MrBayes、TNT构建系统发育树
  14. shell编程三大神器之sed
  15. 借助Amazon EMR与外部KDC进行身份认证,有效集成业务场景
  16. 全球一月内两次遭到病毒暴击 2017网络安全生态峰会或有解药
  17. 【慕课网】JavaScript中函数和this
  18. Python3.7,在Anaconda中安装PIL
  19. STM32F0xx定时器输出PWM配置
  20. 老船履带工具使用方法_上蔡县履带自动行走洛阳铲安全好操作

热门文章

  1. edgewin10无法安装_处理win10无法打开edge怎么解决
  2. OpenJudge 7624 山区建小学
  3. GBase 8c数据库登陆
  4. 163vip邮箱全面体验测评分享
  5. 时钟显示(C语言实现)
  6. 一文了解同态加密(Homomorphic Encryption, HE)
  7. HTML+CSS 简易搜索框
  8. html 输入框加搜索框,如何实现一个input搜索框?
  9. 路由器php系统时间设置时间设置时间设置,4G工业路由器系统设置与时间密码设置...
  10. org.hibernate.hql.internal.ast.QuerySyntaxException