0.0
- Hooks 是 react 在16.8.0版本新增的新语法
- 可以让你在函数组件中使用 state 和其他的 react 特性
-
为什么用
类组件很难复用状态逻辑
- 复杂组件难以理解,尤其生命周期函数,有时还要两个生命周期函数中对照修改代码,甚至要写同样逻辑的代码
- react组件一直都更像是函数,使用hook使得完全拥抱函数
常用 Hook
State Hook: useState()
函数式组件中,this 为 undefined ,state 就更没有了。便可以通过这个 Hook 使用 state,使得函数组件也有可操作的状态
语法const [state, setstate] = useState(initialState)
在引入 react 时,就不用引入 Component,而是引入 useState 这个方法了
state 是状态, setState 就是操作状态的那个方法了
与组件那个控制状态的方法 也有区别:那个是合并更新,而这个是覆盖更新。
setState ()2种写法:
- setState (newValue): 参数为非函数值, 直接指定新的状态值, 内部用其覆盖原来的状态值
- setState (value => newValue): 参数为函数, 接收原本的状态值, 返回新的状态值, 内部用其覆盖原来的状态
Effect Hook:useEffect()
用于模拟类组件中的生命周期钩子(副作用操作)
- 例如
- 异步操作:发ajax请求数据获取
- 设置订阅 / 启动定时器
- 手动更改真实DOM
可以在一个函数组件中设置多个 useEffect
语法
useEffect(() => {
effect // 在此可以执行任何带副作用操作
return () => {// 在组件卸载前执行
cleanup // 在此做一些收尾工作, 比如清除定时器/取消订阅等
}
}, [input])// 如果指定的是[], 回调函数只会在第一次render()后执行
可以视作以下三个钩子的集合 (其实这样理解不是特别好,但我刚开始学习的时候确实是这样理解的。)
- componentDidMount()
- componentDidUpdate()
- componentWillUnmount()
异步操作
如果是用 fetch ,可以直接操作。
但是这里面不支持 直接使用await 、 async
,但是也提供了解决方法 ```jsx const Index = ()=>{ useEffect(()=>{
demo() //直接调用该方法 }) return <></> } //或者将 async 方法放在useEffect 外面async function demo(){}
async function demo(){}
const Index = ()=>{ useEffect(()=>{ demo() //直接调用该方法 }) return <></> }
<a name="NWN35"></a>
### useLayoutEffect
和前者的区别就是,它是在所有的DOM渲染完毕之后**同步**执行 Effect,一般在这里面进行**DOM相关操作,**改变浏览器的一些显示效果
<a name="Mc9x5"></a>
### useMemo
没用这个的时候,当一个组件中的一个属性被改变,那么整个组件——包括与改变的属性无关的部分——都会被重新渲染,就会影响性能。而用memo设置出来的属性相关的东西,就只会在该属性改变时才重新渲染
```jsx
//函数组件内部:
const [text,setText] = useState("aa")
const memoText = useMemo(()=>{
//console.log("memo")
return text
},[text])
useCallback
也与缓存相关,主要用来缓存相关的函数
const handleClickCount = useCallback(()=>{
setCount(count+1)
},[count])
Ref Hook: useRef()
语法
const ref = useRef(initialValue)
其用法与类组件中的 ref 的 createRef() 相似
- 主要作用是 让状态数据之间有更为紧密的关系,各个部分render时操作同一个唯一的值引用
-
useReducer
const [state, dispatch] = useReducer(
reducer,
initialState
);
同 redux 中的 reducer ,The reducer takes in the initialState and the action, so based on the action type, the reducer returns a new state object.
reducer 是接收 state、action 两个参数,根据action.type 进行对应的操作,返回修改后的 stateuseContext
const {state, dispatch} = useContext(UserContext)
code
现在我将各个 hook 与类组件中对应的东西横向比较,两段代码的页面效果是一样的。
类组件版本class Demo extends Component {
state = { count: 0 };
myRef = React.createRef()
add1 = () => {
this.setState(state => ({ count: state.count + 1 }));
};
unmount = () => {
ReactDom.unmountComponentAtNode(document.getElementById("root"));
};
show=()=>{
alert(this.myRef.current.value)
}
componentDidMount() {
this.timer = setInterval(() => {
this.setState(state => ({ count: state.count + 1 }));
}, 500);
}
componentWillUnmount() {
clearInterval(this.timer);
}
render() {
return (
<div>
<input type="text" ref={this.myRef}/>
<h1>现在求和为{this.state.count}</h1>
<button onClick={this.add1}>点我加1</button>
<button onClick={this.unmount}>卸载组件</button>
<button onClick={this.show}>点击提示数据</button>
</div>
);
}
函数组件版本
function Demo() {
const [count, setCount] = React.useState(0);
const myRef = React.useRef()
React.useEffect(() => {
const timer = setInterval(() => {
setCount(count => count + 1);
}, 500)
return ()=>{
clearInterval(timer)
}
}, []);
function add1() {
// setCount(count + 1);
setCount(count => count + 1);
}
function unmount() {
ReactDom.unmountComponentAtNode(document.getElementById("root"));
}
function show(){
alert(myRef.current.value)
}
return (
<div>
<input type="text" ref={myRef} />
<h1>现在求和为{count}</h1>
<button onClick={add1}>点我加1</button>
<button onClick={unmount}>卸载组件</button>
<button onClick={show}>点击提示数据</button>
</div>
);
}
自定义hook
总结
没有this导致class中很多东西没有
- 没有生命周期钩子
- 但都有别的方法完成
- 看明白code就可以了
注意:
- 只在最顶层使用hook
- 只在react函数中调用hook