一、react hooks的作用
react hooks 是react 16.8的功能,对函数型组件进行增强,让函数组件可以存储状态,可以拥有处理副作用的能力。让开发者在不使用类组件的情况下,实现相同的功能。
二、react hook要解决的问题
react hooks的产生是为了解决react 类组件的不足,react 类组件的不足主要表现在以下方面:
- 缺少逻辑复用机制:react 类组件中,为了实现逻辑复用机制,通常使用的是高阶组件和渲染属性,为了实现逻辑复用,增加了无实际渲染效果的组件,增加了组件层级,使整个组件显得很臃肿,同时增加了调试难度及组件运行时的效率。
- 类组件经常会变得很复杂并难以维护:将一组相干的业务逻辑拆分到了多个生命周期函数中,在一个生命周期函数中,会存在多个不相干的业务逻辑。
- 类成员函数不能不能保证this指向的正确性?
三、react hook的使用
react hooks是一些钩子函数,react通过这些钩子函数对函数型组件进行增强,并且不同的钩子函数提供了不同的功能。
3.1、useState()
作用:可以使一个函数型组件可以保存自己的状态,内部使用闭包实现。
使用细节:
- 接收唯一的参数即状态初始值,初始值可以使任意js数据类型。
- 返回值维数组.数组中存储状态和改变状态值的方法,方法名约定以set开头,再加上状态名。
- useState()在同一个组件中可以被调用多次,用以存储不同的状态。
- 参数还可以是一个函数,初始状态是函数返回值,函数只会被调用一次,适用于初始值是动态的情况。
- 设置状态值方法的参数可以是一个值也可以是一个函数。
- 设置状态值方法的方法本身是异步的。
import React, { useState } from 'react'
function App(props) {
// const [count, setCount] = useState(0)
const [count, setCount] = useState(() => {
return props.count || 0 // 只会被调用一次
})
const [person, setPerson] = useState({name: 'zhangsan', age: 20})
return (
<div>
<span>{count} {person.name} {person.age}</span>
<button onClick={() => setCount(count + 1)}>+ 1</button>
<button onClick={() => setPerson({...person, name: 'lisi'})}>
setPerson
</button>
</div>
)
}
export default App
3.2、useReducer()
作用:useReducer是另一种让函数组件保存状态的方式。相较于useState,使用useReducer时,子组件可以调用父组件传递的?dispatch方法来修改父组件的状态,而不需要传递繁多的改变状态的方法,比较方便。
import React, {useReducer} from 'react'
function App() {
function reducer (state, action) {
switch (action.type) {
case 'increment':
return state + 1
case 'decrement':
return state - 1
default:
return state
}
}
const [count, dispatch] = useReducer(reducer, 0)
return (
<div>
<button onClick={() => dispatch({type: 'increment'})}>+1</button>
<span></span>
<button onClick={() => dispatch({type: 'decrement'})}>-1</button>
</div>
)
}
export default App
3.3、useContext()?
作用:在跨组件层级获取数据时简化获取数据的代码。
使用细节:
- 接收一个 context 对象(
React.createContext ?的返回值)并返回该 context 的当前值。 - 组件当前的 context 值由上层组件中距离当前组件最近的 context的?
value ?prop 决定。 - 当组件上层最近的?
<MyContext.Provider> ?更新时,该 Hook 会触发重渲染,并使用最新传递给?MyContext ?provider 的 context?value ?值。
import React, { createContext, useContext } from 'react'
const countContext = createContext()
function App() {
return (
<countContext.Provider value={100}>
<Foo />
</countContext.Provider>
)
}
function Foo() {
const value = useContext(countContext)
return <div>我是Foo组件{value}</div>
}
export default App
3.4 useEffect()
作用:让函数型组件拥有处理副作用的能力,类似于生命周期。
执行时机:useEffect()的作用相当于类组件componentDidMount 、componentDidUpdate、componentWillUnmont三个生命周期函数的组合。
- useEffect(() => {})? 相当于?
componentDidMount 、componentDidUpdate - useEffect(() => {},[]) 相当于
componentDidMount,只在组件挂载完成执行一次 - useEffect(() => () => {}) 相当于
componentWillUnmont,通常处理一些清除工作
好处:
- 按照用途将代码进行分类(将一组相干的业务逻辑归置到了同一个useEffect中)
- 大大简化重复代码,使代码解构更加清晰明了
import React, { useState, useEffect } from 'react'
import { ReactDOM } from 'react-dom'
function App() {
const [count, setCount] = useState(0)
function onScroll() {
console.log('页面发生滚动了')
}
// 监听页面滚动
useEffect(()=> {
// 在组件加载完成后,增加监听
window.addEventListener('scroll', onScroll)
// 在组件卸载前,移除监听
return () => {
window.removeEventListener('scroll', onScroll)
}
}, [])
// 组件加载完成时,增加定时器
useEffect(() => {
const timer = setInterval(() => {
setCount(count => {
document.title = count + 1
return count + 1
})
}, 1000);
// 组件卸载时,清除定时器
return () => {
clearInterval(timer)
}
}, [])
return <div>
<span>{count}</span>
<button onClick={() =>
ReactDOM.unmountComponentAtNode(document.getElementById('root'))}>
卸载组件
</button>
</div>
}
export default App
使用细节:
- useEffect()的第二个参数是一个数组,表示只有指定数据发生变化的时候才会触发effect。
- ?useEffect()结合异步函数:useEffect中的参数函数不能是异步函数,因为useEffect函数要返回清理资源的函数,如果是异步函数就变成了返回Promise。
- useEffect()结合异步函数的正确方式如下:
useEffect(() => {
(async () => {
await axios.get()
})()
})
3.5?useMemo()? 作用: -
类似于vue中的计算属性,可以监测某个值的变化,从而计算出新值。 -
useMemo()会缓存计算结果,如果被监测数据未发生变化,即使组件重新渲染,也不会重新计算,因此,可以避免在每个渲染上进行昂贵的计算。 -
第二个参数为被监测的数据,是一个数组,代表可以同时监听多个数据。 -
useMemo的返回值为计算出来的新值。
? ?使用方式:?
import { useMemo } from 'react'
// result为计算的新值
const result = useMemo(() => {
// 被监测值发生变化时,执行的操作
}, [count])
?如下例子:
import React, { useState, useMemo } from 'react'
function App() {
const [count, setCount] = useState(0)
const result = useMemo(() => {
return count * 2
}, [count])
return (
<div>
<div>原值:{count} 新值:{result}</div>
<button onClick={() => setCount(count + 1)}>+1</button>
</div>
)
}
export default App
?3.6?memo()?
memo()作用:如果本组件中的数据没有发生变化,阻止组件更新,主要用于组件的性能优化。类似于类组件中的pureComponent()和shouldComponentUpdate()。
用法:
import React, { memo } from 'react'
function Counter() {
return <div>counter</div>
}
export default memo(Counter)
?
|