文章目录
1. 为什么使用HOOKS?
让函数式组件具有类组件的能力
2. 以下通过一个页面计时器的方法来介绍hook api
1. 先使用原来类组件的方式编写
import Reactl from 'react'
class MyCount extends React.Component {
state = {
count: 0
}
componentDidMount() {
this.interval = setInterval(() => {
this.setState({ count: this.state.count + 1 })
}, 1000);
};
componentwillUnmount() {
if (this.interval) { clearInterval(this.interval) }
}
render() {
return <span>{this.state.count}</span>
}
}
export default MyCount;
2. useState 和 useEffects(后面详细介绍)
const [count, setCount] = useState(0)
通过useState 可以让函数组件拥有类组价的 state
因为 函数式组件没有钩子函数 就需要用到useEffect
使用 hooks 改造如下
import React, {useState, useEffect} from 'react'
function MyCountFunc() {
const [count, setCount] = useState(0)
// hooks没有钩子函数概念 所以引入 useEffect
useEffect(() => {
const interval = setInterval(() => {
// setCount(count + 1) // 不会实现更新数据
setCount((count) => count + 1 )
}, 1000);
return () => clearInterval(interval); // 卸载的时候会执行
})
return <span>{count}</span>
}
export default MyCountFunc;
通过useState 生命完成后 会返回一个数组
const [count, setCount] = useState(0) // [a, b]
useState 中的默认值 只会在页面进来的时候加载第一次使用
在修改 useState 中的数据时 有两种放肆
- 1、直接传入值进行修改 setCount(1)
- 2、 传入一个callBack 并且要有返回值 setCount(© => c+1 )
以上两个方法都可进行修 useState 中声明的值,但是:
方法1:是不基于最新的count 来更新
方法2:通过回调函数的方式 是可以基于当前值来更新数据的 可以避免数据不更新问题
3. useReducer
const [count, dispatchCount] = useReducer(countReducer, 0)
countReducer() 接收两个参数 1、传入的countReducer 函数 2、默认值
import React, { useReducer, useEffect } from 'react';
const countReducer = (state, action) => {
switch (action.type) {
case 'add':
return state + 1;
case 'minus':
return state - 1;
default:
return state;
}
}
const MyCountFunc = () => {
const [count, dispatchCount] = useReducer(countReducer, 0)
useEffect(() => {
const interval = setInterval(() => {
dispatchCount({type: 'minus'});
}, 1000)
return () => clearInterval(interval)
}, [])
return (
<div>
counts: {count}
</div>
)
}
export default MyCountFunc;
4. useEffect
- useEffect(() =>{return effect},[])
- useEffect有两个参数, 第一个是调用函数, 第二个是监听值.
- 调用函数 在组价加载完执行, return 出来的函数 是在组件卸载时执行
- 第二个参数是一个数组,你可以理解为他是你所要监听的数据,数据变化了才会执行 useEffect
- 如果你熟悉 React class 的生命周期函数,你可以把 useEffect Hook 看做
componentDidMount,componentDidUpdate 和 componentWillUnmount
这三个函数的组合。- 第二个参数不传 相当于 componentDidUpdate
- 第二个参数传入 [] 相当于componentDidMount
- 第一个是调用函数 直接 return 出一个函数 叫销毁函数 相当于 componentWillUnmount
以上只是模拟相等并不代表完全相等
import React, {useReducer, useState, useEffect } from 'react';
const countReducer = (state, action) => {
switch (action.type) {
case 'add':
return state + 1;
case 'minus':
return state - 1;
default:
return state;
}
}
const HooksUseEffect = () => {
const [count, dispatchCount] = useReducer(countReducer, 0)
const [name, setName] = useState('kings');
useEffect(() => {
console.log('useEffect')
return () => console.log('useEffect calback')
}, [count])
return (
<div>
<input value={name} onChange={(e) => {
setName(e.target.value)
}} />
<button onClick={() => dispatchCount({type: 'add'})}>{count}</button>
</div>
)
}
export default HooksUseEffect;
5.useLayoutEffect
他和 useEffect 的区别就是,useEffect是等待Dom 节点加载完成后 再去执行。而useLayoutEffect 是在dom 加载完成之前执行,如果进行逻辑处理很多业务很麻烦的时候 他就会阻塞页面展示,一般不适用。
6. useContext
占位
7. useRef
import React, {useState, useEffect, useRef } from 'react';
const HooksUseEef = () => {
const [name, setName] = useState('kings');
const inputRef = useRef();
useEffect(() => {
console.log(inputRef.current.value)
return () => console.log('useEffect calback')
}, [name])
return (
<div>
<input ref={inputRef} value={name} onChange={(e) => {
setName(e.target.value)
}} />
</div>
)
}
export default HooksUseEef;
8、hooks 的优化 memo AND useMemo AND useCallback
在父组件调用子组件的时候,父组件数据更新了就会导致子组件重新渲染。可以使用memo 处理子组件,并且在父组件变化的数据使用useMemo(fun,[])来处理,useCallback(fun,[])来传入父组件操作的函数
import React, { useReducer, useState, useEffect, useMemo,memo, useCallback } from 'react';
const countReducer = (state, action) => {
switch (action.type) {
case 'add':
return state + 1;
case 'minus':
return state - 1;
default:
return state;
}
}
const MyCountFunc = () => {
const [count, dispatchCount] = useReducer(countReducer, 0)
const [name, setName] = useState('kings');
// const config = {
// text: `count is ${count}`,
// color: count > 3 ? 'red' : 'blue'
// }
const config = useMemo(() => ({
text: `count is ${count}`,
color: count > 3 ? 'red' : 'blue'
}), [count])
// const handleClick = () => {
// dispatchCount({ type: 'add' })
// }
// const handleClick = useCallback(() => {
// return dispatchCount({ type: 'add' })
// }, []);
const handleClick = useMemo(() => () =>{
dispatchCount({ type: 'add' });
}, []);
return (
<div>
<input value={name} onChange={(e) => {
setName(e.target.value)
}} />
<Child
config={config}
onButtonClick={handleClick}
/>
</div>
)
};
const Child = memo(function Child({ onButtonClick, config }) {
console.log('Child render')
return (
<button onClick={onButtonClick} style={{ color: config.color }}>
{config.text}
</button>
)
});
export default MyCountFunc;
9、闭包陷阱
通过ref 可以避免
未完待续。。。