为什么用react-hook
在组件之间复用状态逻辑很难
可能你会使用render props或者高阶组件,但一方面,组件结构需要变动,使用render props和高阶组件也会使组件变得很难理解,另一方面会形成嵌套地狱,在用devtools排查问题时,很不方便。
复杂组件变得难以理解
在此之前,我们可能要关注各种生命周期(虽然也写过一篇react生命周期的文章),componentDidMount,componentDidUpdate等等。举自己曾经在实际项目中的两个例子:
- componentDidMount里面发了n个请求,componentWillRecieveProps里面做了判断后,又发请求。
- componentDidMount添加了addEventListener,componentWillUnmount去removeEventListener。
- 如果1和2再混在同一个组件里面
想想,如果不是自己写的代码,去理解比较困难,其次,如果突然你去维护这样的代码,可能一不小心就把分散在其他地方的业务逻辑忘掉了,导致出现bug,就要背锅了。
难以理解的 class
不止一次面试中问别人,以及被问过,react组件中constructor内绑定事件,箭头函数,bind绑定事件,都是怎么回事,就巴拉巴拉开始说,constructor只执行一次,箭头函数this是指向上下文的,bind每次都会重新生成函数什么什么的。
再者,可能还要区分什么可以写成无状态组件,负责UI,什么组件要用Component,什么组件要用PureComponent。 hook
使我们从面向生命周期编程,到面向实际业务编程。
异步执行,性能更好
与 componentDidMount 或 componentDidUpdate 不同,使用 useEffect 调度的 effect 不会阻塞浏览器更新屏幕,这让你的 应用看起来响应更快。大多数情况下,effect 不需要同步地执 行。
使用多个 Effect 实现关注点分离
使用 Hook解决 class 中生命周期函数经常包含不相关的逻辑,但又把相关逻辑分离到了几个不同方法中的问题。
Hook是什么?
就是以 use
开头的一系列函数,可以让我们在函数当中使用state其他的react特性。不得不感慨前端更新太快,做前端好难,不过还是要不断学习进步,知晓设计的初衷,知晓怎么用,再知晓其原理,干,就对了。
常用的官方hook API
useState
和 class
的 state
一样,useState
产生的 state
表示随着时间(用户交互)发生改变,值也会发生改变的量
const RenderFunctionComponent = () {
const [state, setState] = useState("Hello world!");
return (
<Button onClick={() => setState("Hi world!")}>{state}</Button>
);
}
useReducer
一个useState的替代方案,就像一个简易的redux
const initialState = {count: 0};
function reducer(state, action) {
switch (action.type) {
case 'increment':
return {count: state.count + 1};
case 'decrement':
return {count: state.count - 1};
default:
throw new Error();
}
}
function Counter() {
const [state, dispatch] = useReducer(reducer, initialState);
return (
<>
Count: {state.count}
<button onClick={() => dispatch({type: 'decrement'})}>-</button>
<button onClick={() => dispatch({type: 'increment'})}>+</button>
</>
);
}
useEffect
使用 useEffect 可以用来执行副作用,何为副作用?意思是修改了自我作用域之外的状态,或者除return外,与作用域之外的函数有交互。
在项目中应用广泛,用于初始数据的请求,初始事件的绑定与销毁。中间态的请求(只需要设置useEffect的依赖即可)
- 一个
class
和hook
的官方例子对比
class Example extends React.Component {
constructor(props) {
super(props);
this.state = {
count: 0
};
}
componentDidMount() {
document.title = `You clicked ${this.state.count} times`;
}
componentDidUpdate() {
document.title = `You clicked ${this.state.count} times`;
}
render() {
return (
<div>
<p>You clicked {this.state.count} times</p>
<button onClick={() => this.setState({ count: this.state.count + 1 })}>
Click me
</button>
</div>
);
}
}
import { useState, useEffect } from 'react';
function Example() {
const [count, setCount] = useState(0);
useEffect(() => {
document.title = `You clicked ${count} times`;
});
return (
<div>
<p>You clicked {count} times</p>
<button onClick={() => setCount(count + 1)}>
Click me
</button>
</div>
);
}
- 一个有搜索功能组件的
useEffects
import React, { useState, useEffect } from "react";
import ReactDOM from "react-dom";
import "antd/dist/antd.css";
import "./index.css";
import { Input } from "antd";
const RenderFunctionComponent = () => {
const [searchValue, setSearchValue] = useState();
useEffect(() => {
const getList = async () => {
}
getList();
}, [searchValue]);
return (
<>
<Input value={searchValue} onChange={e=> setSearchValue(e.target.value)}/>
</>
);
}
需注意的是:
- useEffect第二个参数如果为空,则只执行一次(事件绑定是一个场景),如果没有第二个参数,则每次渲染均会执行。
- 可根据业务的不同划分成多个useEffect,而不用像class组件那样,只能在生命周期中书写,关注业务点分离
- 可在 react 内置的 hook api 基础上实现自定义 hook,实现逻辑复用
useContext
获取context提供的值
const value = useContext(MyContext);
useLayoutEffect
在浏览器执行绘制之前,useLayoutEffect
内部的更新计划将被同步刷新
尽可能使用标准的 useEffect
以避免阻塞视觉更新。
useRef
可存储任意变量
function TextInputWithFocusButton() {
const inputEl = useRef(null);
const onButtonClick = () => {
// `current` 指向已挂载到 DOM 上的文本输入元素
inputEl.current.focus();
};
return (
<>
<input ref={inputEl} type="text" />
<button onClick={onButtonClick}>Focus the input</button>
</>
);
}
useCallback
返回一个 memoized 的函数(注意不要滥用:记住函数,以及比较是否需要生成新的函数,未必性能就比串讲一个函数性能好。向下传递回调时可以使用,也可使用useReducer的dispatch向下传递)
const memoizedCallback = useCallback(
() => {
doSomething(a, b);
},
[a, b],
);
useMemo
返回一个 memoized 的值(注意不要滥用:在计算开销比较大时,建议采用)
const memoizedValue = useMemo(() => computeExpensiveValue(a, b), [a, b]);
结语
有人就说了,官方的 hook
那么少,写代码还要自己封装很多自定义的 hook
。不得不说,世界上大佬那么多,为什么人家那么聪明,还比我们努力。
想了解更多 hook
,请看下篇:
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。