将一些常用的、跨越多个组件的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. 很多组件都需要在第一次加载完成后,启动一个计时器,然后在组件销毁时清除计时器```jsxfunction useTimer(func, duration){useEffect(()=>{const timer = setInterval(func, duration);return ()=>{clearInterval(timer);}}, []);}
