将一些常用的、跨越多个组件的HOOK功能,抽离出去形成一个函数,该函数就是自定义HOOK
自定义HOOK,由于其内部需要使用HOOK功能,所以它本身也需要按照HOOK的规则实现
- 函数名必须以use开头,小驼峰
- 调用自定义HOOK函数时,应放到顶层,不能放在循环、判断中
使用hook的时候,如果没有严格按照hook的规则进行编码,则eslint的一个插件(eslint-plugin-react-hooks) 会报出警告。 如何忽略?可以在具体文件下书写如下代码: / eslint “react-hooks/exhaustive-deps”: “off” /
例如:
- 很多组件都需要在第一次加载完成后,获取所有学生数据,再设置状态
这是自定义hook的方式:
function useAllStudents(){
const [ students, setStudents ] = useState([]);
useEffect(()=>{
(async ()=>{
const stus = await getAllStudents();
setStudents(stus);
})();//useEffect中不能返回一个Promise,所以需要把这个async写为IIFE
}, []);
}
function Test(props){
const stus = useAllStudents();
const list = stus.map(it => <li key={it.id}>it.name</li>);
return (<ul>
{list}
</ul>);
}
export default function App() {
return (
<div>
<Test />
</div>
)
}
以前类组件呢,倒是也能这样,用高阶组件的的方式,但是太麻烦,而且导致结构层次变深
function willAllStudents(Comp){//传一个组件进来
return class AllStudentsWrapper extends React.Component{
state = {
stus: []
}
async componentDidMount(){
const stus = await getAllStudents();
this.setState({
stus,
})
}
render(){
return <Comp {...this.props} stus={this.state.stus}></Comp>
}
}
}
function Test(props){
const list = props.stus.map(it => <li key={it.id}>it.name</li>);
return (<ul>
{list}
</ul>);
}
const TestStudents = withAllStudents(Test);
export default function App() {
return (
<div>
<TestStudents />
</div>
)
}
HOOK的出现很好的解决了横向关注点,而且可以很好的拆分纯函数与副作用
- 根据页码和页容量获取学生数据,得到一个相应结果,并且页码或页容量变化时,将重新获取学生数据
```jsx
function usePageStudents(page=1, limit=10){
const [resp, setResp] = useState({});
useEffect(()=>{
}, [page, limit]); }(async ()=>{
const resp = await getAllStudents(page, limit);
setResp(resp);
})();
function Test2(){ const [page, setPage] = useState(1); const resp = usePageStudents(page, 10); if(resp){ const list = resp.findByPage.map(it=>
数据总数:{resp.cont}
- {list}
);
}else{
return null;
}
}
3. 很多组件都需要在第一次加载完成后,启动一个计时器,然后在组件销毁时清除计时器
```jsx
function useTimer(func, duration){
useEffect(()=>{
const timer = setInterval(func, duration);
return ()=>{
clearInterval(timer);
}
}, []);
}