欢迎来到我的博客
博主是一名大学在读本科生,主要学习方向是前端。
目前已经更新了【Vue】、【React–从基础到实战】、【TypeScript】等等系列专栏
目前正在学习的是 R e a c t 框架 React框架 React框架,中间穿插了一些基础知识的回顾
博客主页codeMak1r.小新的博客本文目录
- React Hooks/Hooks是什么?
- Hooks解决了什么问题?
- Hooks优势总结
- 三个常用的Hook
- 1.State Hook
- 示例
- 等价的 class 示例
- 2.Effect Hook
- 示例
- 3.Ref Hook
- 示例
- 阶段小练习 - 自定义hook
本文被专栏【React–从基础到实战】收录
本节任务:
能够理解hooks的概念以及解决的问题
文章末尾有两个小案例,相信看完文章的你可以自己把小案例实现出来~
Hooks的本质:一套能够使函数组件更加强大,更加灵活的“钩子”
React体系里组件分为类组件 和 函数式组件。
经过多年实战,函数组件是一个更加匹配React的设计理念UI = f(data)
,也更有利于逻辑拆分与重用的组件表达形式,而先前的函数组件是不可以有自己的状态的,为了能让函数组件可以拥有自己的状态,所以从react v16.8开始,Hooks应运而生。
注意:
Hooks的出现解决了两个问题:1. 组件的状态逻辑复用; 2. class组件自身的问题
在hooks出现之前,react先后尝试了 mixin 混入,HOC高阶组件,render-props等模式…但是都有各自的问题,比如 mixin
的数据来源不清晰,高阶组件HOC
的嵌套问题等等…
class组件就像一个厚重的战舰
一样,大而全,提供了很多东西,有不可忽视的学习成本,比如各种生命周期,this指向问题等等,而我们更多时候需要的是一个轻快灵活的快艇
。
(1) S t a t e H o o k : R e a c t . u s e S t a t e ( ) State Hook:React.useState() StateHook:React.useState()
(2) E f f e c t H o o k : R e a c t . u s e E f f e c t ( ) Effect Hook:React.useEffect() EffectHook:React.useEffect()
(3) R e f H o o k : R e a c t . u s e R e f ( ) Ref Hook:React.useRef() RefHook:React.useRef()
State Hook让函数组件也可以有state状态,并进行状态数据的读写操作;
语法:
const [xxx, setXxx] = React.useState(initValue)
useState()说明:
参数:第一次初始化指定的值在内部作缓存;
返回值:包含2个元素的数组,第1个为内部当前状态值,第2个为更新状态值的函数;
setXxx()2种写法:
setXxx(newValue):参数为非函数值,直接指定新的状态值,内部用其覆盖原来的状态值;
setXxx(value => newValue):参数为函数,接收原本的状态值,返回新的状态值,内部用其覆盖原来的状态值
import React, { useState } from 'react';
function Example() {
// 声明一个叫 "count" 的 state 变量
const [count, setCount] = useState(0);
return (
<div>
<p>You clicked {count} times</p>
<button onClick={() => setCount(count + 1)}>
Click me
</button>
</div>
);
}
class Example extends React.Component {
constructor(props) {
super(props);
this.state = {
count: 0
};
}
render() {
return (
<div>
<p>You clicked {this.state.count} times</p>
<button onClick={() => this.setState({ count: this.state.count + 1 })}>
Click me
</button>
</div>
);
}
}
state 初始值为
{ count: 0 }
,当用户点击按钮后,我们通过调用this.setState()
来增加state.count
。
Effect Hook 可以让你在函数组件中执行副作用操作(用于模拟类式组件中的生命周期钩子)
React中的副作用操作:
(1)发送ajax请求获取数据
(2)设置订阅/ 启动定时器
(3)手动更改真实DOM
语法和说明:
useEffect(() => { // 在此可以执行任何带副作用操作 return () = > { //componentWillUnmount // 做一些收尾的工作,比如清除定时器/取消订阅等等... } },[stateValue]) //如果指定的是[],useEffect第一个参数的回调函数相当于componentDidMount()
可以把 useEffect Hook 看做如下三个函数的组合:
componentDidMount()
componentDidUpdate()
componentWillUnmount()
useEffect第二个参数传入不同的值:
useEffect第二个参数 | useEffect第一个参数相当于 | 理解 |
---|---|---|
不传第二个参数 |
componentDidMount() + componentDidUpdate() |
组件挂载时会调用; 并且所有的state都会监测 |
传入空数组:[] | componentDidMount | 组件挂载时会调用; 并且所有的state都不监测 |
传入数组:[stateValue] 比如:[count] |
componentDidMount + count状态改变时的componentDidUpdate() |
组件挂载时会调用; 并且监测count的改变 |
useEffect第一个参数返回值:
useEffect(() => {
let timer = setInterval(() => {
setCount(count => count + 1)
}, 1000)
return () => {
console.log('componentWillUnmount')
clearInterval(timer)
}
}, [])
useEffect第一个参数的返回值是一个函数,就相当于生命周期函数:componentWillUnmount()
import React, { useState, useEffect } from 'react';
import root from '../../index'
export default function Demo() {
const [count, setCount] = useState(0)
useEffect(() => {
let timer = setInterval(() => {
setCount(count => count + 1)
}, 1000)
return () => {
console.log('componentWillUnmount')
clearInterval(timer)
}
}, [])
function increment() {
// setCount(count + 1)
setCount((count) => {
return count + 1
})
}
function unmount() {
root.unmount();
}
return (
<div>
<h2>当前求和为:{count}</h2>
<button onClick={increment}>点我+1</button>
<button onClick={unmount}>卸载组件</button>
</div>
)
}
Ref Hook 可以在函数组件中存储/查找组件内的标签或者任意其他数据;
语法:
const refContainer = useRef()
作用:保存标签对象,功能与React.createRef()一样
// 创建容器
const myRef = useRef()
// 绑定容器
<input type="text" ref={myRef} />
<button onClick={show}>点我展示数据</button>
function show() {
// console.log(myRef)
alert(myRef.current.value)
}
1.需求描述:自定义一个hook函数,实现获取滚动距离Y
const [ y ] = useWindowScroll() y就是滚动到顶部的距离
每次都有两次控制台输出是因为:React的StrictMode严格模式,忽略第二个输出即可。
import { useState } from 'react';
export default function useWindowScroll() {
const [y, setY] = useState(0)
// 在滚动行为发生的时候,不断获取滚动值,然后交给y
window.addEventListener('scroll', () => {
const h = document.documentElement.scrollTop
setY(y => h)
})
return [y]
}
import React from 'react'
import useWindowScroll from './components/9_hooks_useWindowScroll'
export default function App() {
const [y] = useWindowScroll()
console.log(y)
return (
<div style={{ height: '12000px' }}>
</div>
)
}
2.需求描述:自定义hook函数,可以自动同步到本地LocalStorage
import { useState, useEffect } from 'react'
export default function useLocalStorage(key, defaultValue) {
const [message, setMessage] = useState(defaultValue)
// 每次只要message变化,就会自动同步到本地LocalStorage
useEffect(() => {
window.localStorage.setItem(key, message)
}, [message, key])
return [message, setMessage]
}
import React from 'react'
import useLocalStorage from './components/10_hooks_useLocalStorage'
export default function App() {
const [message, setMessage] = useLocalStorage('hook-key', 'tom')
setTimeout(() => {
setMessage('abc-message')
}, 5000)
return (
<div>
<h4>{message}</h4>
</div>
)
}