React Hooks 入门指南

一、简单介绍一下Hooks

1.Hooks出现的意义

react组件的创建方式有两种: 类组件和函数组件.在以往开发类组件的时候, 每一个类都有自己的状态, 但是在函数组件中是没有状态的概念的.

react组件的状态是什么? 组件的状态(state)是一个对象,它包含某些信息,这些信息可能在组件的生命周期中发生更改。开发时只需更新组件的 state,然后根据新的 state 重新渲染用户界面(不要操作 DOM)。

那么在Hooks出现之后呢, 才让函数组件出现了状态这个概念, 每一个函数组件的状态独立管理.

并且在以往类组件开发组件的时候, 类组件想要复用, 要遵循类组件的规则, Hooks出现后, 可以让我们更加灵活的创建自己的组件.

总结下来React Hooks出现的意义:

  • Hooks之间的状态是独立的, 有自己的独立上下文, 不会出现混淆情况.
  • 让函数组件有了状态管理.
  • 解决了组件树不直观, 类组件难维护.逻辑不复用的问题
  • 由于函数每次渲染都会执行, 所以React中多了一种状态控制, 传入第二个参数. 这样就可以避免函数重复执行

2. 为什么要学习Hooks?

  • 高效开发
  • 提高组件的复用性.(函数组件)
  • 提高逻辑的复用性
  • 提升性能
  • 实现更复杂的功能

3. Hooks的具体使用场景

  • 利用Hooks取代生命周期
  • 让函数组件加上状态
  • 组件的辅助函数
  • 处理发送请求
  • 存储数据
  • 做好性能优化

二、React hooks有哪些API

1. useState() : 定义函数组件的状态

作用:

  • 初始化以及更新state
  • 用来声明状态变量
import React, { useState } from “react”

function StateFunction() {
  // 使用useState来创建状态
  // 接收一个参数作为初始值
  // 返回值中第一个参数代表状态变量, 第二个代表修改这个变量的函数
  const [buttonText, setButtonText] = useState(“click me, please”)

  function handleClick() {
	return setButtonText(“Thanks, been clicked!”)
  }

  return <button onClick={handleClick}>{buttonText}</button>
}
export default StateFunction

2. useEffect(): 副作用钩子

作用: 

  • 给没有生命周期的组件, 添加结束渲染的信号.
  • 组件中可以多次使用. 

useEffect()接受两个参数,第一个参数是要进行的异步操作,第二个参数是一个数组,用来给出Effect的依赖项,只要这个数组发生变化,useEffect()就会执行。
当第二项省略不填时。useEffect()会在每次组件渲染时都会执行useEffect,只要更新就会执行。
当第二项传 空数组[ ] 时,只会在组件挂载后运行一次
useEffect()返回值可以是一个函数,在组件销毁的时候会被调用。清理这些副作用可以进行如取消订阅、清除定时器操作,类似于componentWillUnmount。

const Person = ({ personId }) => {
  const [loading, setLoading] = useState(true)
  const [person, setPerson] = useState({})
  // 接收函数作为一个参数
  // 接收一个函数作为参数
  // 接收第二个参数, 依赖列表只有依赖更新时, 才会执行函数
  // 返回一个函数, 先执行返回函数, 在执行参数函数
  useEffect(() => {
	setLoading(true)
	fetch(‘www.api.xxx’)
	  .then(response => response.json())
	  .then(data => {
		 setPerson(data)
		 setLoading(false)
	  })
	  console.log(“函数组件渲染”)
	  return () => {
		console.log(销毁)
	  }
  }, [person])

  if (loading === true) {
	return <p>Loading…</p>
  }
  return 
	<div>
	  <p>name: {person.name}</p>
	</div>
}

可以把 useEffect Hook 看做如下三个函数的组合 :componentDidMount()、componentDidUpdate()、componentWillUnmount()

useEffect Hook是如何模拟声明周期的:

模拟 componentDidMount 和 componentDidUpdate,useEffect 依赖不写
模拟 componentDidMount,useEffect 依赖 []
模拟 componentDidUpdate,useEffect 无依赖,或者依赖 [a, b]
模拟 componentWillUnMount,useEffect 返回一个函数

3. useLayoutEffect: 副作用钩子, 在dom更新完成之后执行某个操作,

与useEffect不同之处: 

  • useEffect执行时机是在render之后, useLayoutEffect是在dom更新之后
  • useEffect是同步的, 而useLayoutEffect是同步的
import React, { useState, useLayoutEffect } from “react”

function StateFunction () {
  const [num, setNum] = useState(1)
  // 接收函数作为一个参数
  // 接收一个函数作为参数
  // 接收第二个参数, 依赖列表只有依赖更新时, 才会执行函数
  // 返回一个函数, 先执行返回函数, 在执行参数函数

  // 不同点 
  // useEffect执行时机是在render之后, useLayoutEffect是在dom更新之后
  // useEffect是同步的, 而useLayoutEffect是同步的
  useLayoutEffect(() =>{
	console.log(‘useLayoutEffect’)
	document.body.addEventListener(‘a’, ()=> {})
	return() => {
	  document.body.removeEventListener(‘a’, ()=> {})
	}
  , [num]) 

  useEffect(() => {
	console.log(‘useEffect’)
  }, [num])

  return <div onClick=“{()=>{ setNum(num => num + 1) }}”></div>
}

export default StateFunction

4. useMemo: 让组件中的函数跟随状态跟新, 返回的是一个值

作用: 主要用来解决使用React hooks产生的无用渲染的性能问题

// 1. 接受一个函数作为参数
// 2. 第二个参数为依赖列表, 对比useEffect、useLayoutEffect
// 3. 返回的是一个值
import React, { useState, useMemo } from “react”
function StateFunction () {
	const [num, setNum] = useState(1)
	const [age, setAge] = useState(18)
	const getDoubleAge = useMemo(()=>{
		console.log(“获取2倍的age”)
		return 2 * num
	}, [age])
	return <div onClick=“{()=>{ setNum(num => num + 1) }}”>
		{ getDoubleAge }
	</div>
}
export default StateFunction

useMemo应用场景:

  • 可以缓存 element 对象,从而达到按条件渲染组件,优化性能的作用。
  • 如果组件中不期望每次 render 都重新计算一些值,可以利用 useMemo 把它缓存起来。
  • 可以把函数和属性缓存起来,作为 PureComponent 的绑定方法,或者配合其他Hooks一起使用

5. useCallback: 组件中的函数跟随状态更新, 返回的是一个函数

作用:

  • 只有依赖项改变的时候才会更新, 为了更好的性能的优化
  • useMemo相当于(() => {}, deps[]), 相当于 useCallback(fn, deps[])
// 1. 只有依赖项改变时, 才会执行
// 2. 在使用方法上, useMemo(()=>fn, deps) 相当于 useCallback(fn, deps)
import React, { useState, useCallback } from “react”
function StateFunction () {
	const [num, setNum] = useState(1)
	const [age, setAge] = useState(18)
	const getDoubleAge = useCallback(()=>{
		console.log(“获取2倍的age”)
		return 2 * num
	}, [age])
	set.add(getDoubleNum)
	console.log(set.size)
//  3. 不同点:  useCallback返回的是一个函数, useMemo返回的是一个值
	return <div onClick=“{()=>{ setNum(num => num + 1) }}”>
		{ getDoubleAge() }
	</div>
	<Child callback={getDoubleNum}></Child>
}
function Child(props) {
	useEffect(() => {
		console.log(‘callback更新了’)
	}, [props.callback])

	return <div>child</div>
}
export default StateFunction

6. userRef: 长久保存数据

作用:

  • 返回一个子元素的索引, 此索引在整个生命周期中保持不变.
  • 对象发生改变, 不通知. 属性变更不重新渲染.

(1) 在整个生命周期中保持一个数据不变

import React, { useState, useEffect, useRef } from “react”
function StateFunction () {
	const [num, setNum] = useState(1)
	const ref = useRef()
	console.log(ref)
	useEffect(() => {
		ref.current = setInterval(() => {
			setNum(num => num + 1)
		}, 400)
	}, []) 
	useEffect(() => {
		if (num > 10) {
			console.log(“超过10了”, ref.current)	
		}
	}, [])
	return <div >{ num }</div>
}
export default StateFunction

(2) 对象放生改变, 不通知. 属性变更不重新渲染

import React, { useState, useEffect, useRef } from “react”
function StateFunction () {
	const [num, setNum] = useState(1)
	const ref = useRef()
	console.log(ref)
	useEffect(() => {
		ref.current = ‘1111’
	}, []) 
	return <div >{ ref.current }</div>
}

7. useContext: 共享状态钩子

作用: 用于组件之间的共享状态 


第一步: 引入useContext、 createContext两个内容
第二步: 通过createContext创建context句柄
第三步: Context.Provider确定数据共享范围
第四步: 通过value分发内容
第五步: 子组件, 通过useContext 传入数据

例: 现在有两个组件Navbar 和 Messages, 我们希望他们之间共享钩子
import React, { useContext } from “react”
const AppContext = React.createContext({});

const Navbar = () => {
	const{ userName } = useContext(AppContext)
	return (
		<div className=“navbar”>
			<p>{ userName }</>
		</div>
	) 
}
const Messages =  () => {
	
	const { userName } = useContext( AppContext )
	return (
		<div className=“message”>
			<p>{ userName }</p>
		</div>
	)
}

function App() {
	return (
		// 
		<AppContext.Provider value={{
			userName: ‘super man’
		}}>
			<div>
				<Navbar />
				<Messages />
			</div>
		</AppContext.Provider>
	)
}

8. useReducer: Action钩子

作用: React本身不提供状态表管理功能, 通常需要使用外部库, 最常用的是redux, Redux最核心的概念是, 组件发出action 与状态管理器通信, 状态管理器收到Action以后, 使用render函数算出新的状态.

useReducer的使用方法: 

1. 需要创建数据仓库 store 和管理者 reducer

2. 通过useReducer ( reducer, store ) 来获取state 和 dispatch

// 使用useRender()钩子用来引入reducer功能
// redux的必备内容
// store reducer
Import React, { useRenducer } from “react”

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>
			<button onClick={() => dispatch({ type: ‘countUp’ })}></button>
			<p>Count: { state.count }</p>
		</div>
	)
}
const rootElement = document.getElementById(“root”)
ReactDOM.render(<APP />, rootElement)

使用useReducer()代替了Redux的功能,但useReducer无法提供中间件等功能,假如有这些需求,还是需要用到redux。

9. 自定义Hooks: 自定义Hooks以支持特殊场景

  • 是一个函数,其名称以 “use” 开头,函数内部可以调用其他的 Hook
  • 可以封装状态,能够更好的实现状态共享
import { useState,useEffect } from "react";
const usePerson = ({name}) => {
    const [loading, setLoading] = useState(true)
    const [person, setPerson] = useState({})

    useEffect(() => {
        setLoading(true)
        setTimeout(()=> {
            setLoading(false)
            setPerson({name})
        },2000)
    },[name])
    return [loading,person]
}
const AsyncPage = (name)=> {
    const [loading,person] = usePerson(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('郭靖')}}>郭靖</button>
            <button onClick={ ()=> { changeName('黄蓉')}}>黄蓉</button>
        </>
    )
}
export default PersonPage;

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值