Hooks理解
react组件分为类组件和函数组件
函数组件是一个更加匹配react的设计理念UI = f(data),利于逻辑拆分与重用的组件表达形式,而之前的函数组件是不可以有自己的状态的,为了能让函数组件可以拥有自己的状态,react16.8开始,Hooks出现
- Hooks出现后,类组件并没有移除,还是可以使用
- Hooks出现有,不能把函数成为无状态组件
- Hooks只能在函数组件中使用
Hooks出现解决的问题:
1,组件的状态逻辑复用
2,claas组件自身的问题
- 告别难以理解的Class
- 解决业务逻辑难以拆分的问题
- 使状态逻辑复用变得简单可行
- 函数组件在设计思想上,更加契合react理念
useState
提供一个状态,以及修改状态的方法,useState后的值表示初始化的值
// useState
// 1,导入useState函数 react
// 2,执行这个函数并且传入初始值,必须在函数组件中
// 3,[数据,修改数据的方法]
// 4,使用数据,修改数据
import { useState } from 'react'
function App () {
// useState返回一个数组,如下是结构赋值的写法
// 名字是可以自定义的 -> 保持语义化
// 顺序不可以换,数组是有序的,第一个参数是数据状态,第二个参数就是修改数据的方法
// setCount是一个函数,作用: 用于修改count状态的值,依旧保持不能直接修改原值,还是用于计算得到的新值替换原值
// count和setCount是绑在一起的
const [count, setCount] = useState(0)
return (
<div>
<button onClick={() => setCount(count + 1)}>{count}</button>
</div>
)
}
更新过程:
// 当调用setCount时,更新过程
// 首次渲染
/**
* 首次被渲染时,组件内部的代码会被执行一次
* 其中useState也会跟着执行
* useState(0)初始值,只在首次渲染时生效
*/
// 更新渲染
/**
* setCount都会更新
* APP组件会再次渲染,这个函数会再次执行
* useState再次执行得到的新的count执行不是0,而是修改后的1,模板会使用新值
*/
useState调用多次,初始化多个状态
function App () {
const [count, setCount] = useState(0)
const [flag, setFlag] = useState(true)
const [list, setList] = useState([1, 2, 3])
console.log(count)
return (
<div>
<button onClick={() => setCount(count + 1)}>{count}</button>
{list.map(item => <h2 key={item}>{item}</h2>)}
</div>
)
}
注意事项:
-
只能出现在函数组件中
-
不能嵌套在if/for/其他函数中(react按照hooks的调用顺序识别每一个hook),如下是错误写法
let name = 'seek' function Show(){ name = 'seek18' // 错误写法 if (name = 'seek18'){ const [age,setAge] = useState(18) } const [flag,setFlag] = useState(true) }
可以通过开发者工具查看hook状态
useEffect
函数的副作用:
一个函数除了主作用,其他的作用就是副作用,对于react组件来说,主作用就是根据数据渲染UI,除此以外都是副作用(例如:手动修改DOM)
常见的副作用:
- ajax请求
- 手动修改dom
- localstorage操作
useEffect函数的作用就是为react函数组件提供副作用处理
import { useEffect, useState } from 'react'
// 在修改数据后,把count值放到页面标题中
// 1,导入useEffect函数
// 2,在函数组件中执行
// 3,当我们通过修改状态更新组件时,副作用也不断执行
function App () {
const [count, setCount] = useState(0)
useEffect(() => {
document.title = count
})
return (
<div>
<button onClick={() => setCount(count + 1)}>{count}</button>
</div>
)
}
export default App
通过依赖项,控制执行实际
1,默认状态
2,添加一个空数组
3,依赖特性项
function App () {
const [count, setCount] = useState(0)
const [name, setName] = useState('seek')
// 默认:组件第一次渲染以及每次更新执行
useEffect(() => {
document.title = count
console.log('每次执行')
})
// 只会在首次渲染执行
useEffect(() => {
console.log('first console')
}, [])
// 添加特定的依赖项,表示只有修改count才会执行,后面是一个数组
useEffect(() => {
console.log('count console')
}, [count])
// 同时修改count和name,或者只改一个都会执行
useEffect(() => {
console.log('count console')
}, [count,name])
return (
<div>
<button onClick={() => setCount(count + 1)}>{count}</button>
<button onClick={() => setName(name + 'a')}>{name}</button>
</div>
)
}
注意事项:
useEffect 回调函数中用到的数据(比如,count)就是依赖数据,就应该出现在依赖项数组中,如果不添加依赖项就会有bug出现
hook的出现,就是不想用生命周期概念,也可以写业务代码
自定义hook函数
自定义一个hook函数,实现获取滚动距离Y,const [y] = useWindowScroll()
import { useEffect, useState } from 'react'
function useWindowScroll () {
const [y, setY] = useState(0)
window.addEventListener('scroll', () => {
const h = document.documentElement.scrollTop
setY(h)
})
return [y]
}
function App () {
const [y] = useWindowScroll()
return (
<div style={{ height: '12000px' }}>
{y}
</div>
)
}
export default App
自定义hook函数,可以自动同步到本地LocalStorage
const [message, setMessage] = useLocalStorage(key,defaultValue)
function useLocalStorage (key, defaultValue) {
const [message, setMessage] = useState(defaultValue)
useEffect(() => {
window.localStorage.setItem(key, message)
}, [key, message])
return [message, setMessage]
}