将一些常用的、跨越多个组件的HOOK功能,抽离出去形成一个函数,该函数就是自定义HOOK
    自定义HOOK,由于其内部需要使用HOOK功能,所以它本身也需要按照HOOK的规则实现

    1. 函数名必须以use开头,小驼峰
    2. 调用自定义HOOK函数时,应放到顶层,不能放在循环、判断中

      使用hook的时候,如果没有严格按照hook的规则进行编码,则eslint的一个插件(eslint-plugin-react-hooks) 会报出警告。 如何忽略?可以在具体文件下书写如下代码: / eslint “react-hooks/exhaustive-deps”: “off” /

    例如:

    1. 很多组件都需要在第一次加载完成后,获取所有学生数据,再设置状态

    这是自定义hook的方式:

    1. function useAllStudents(){
    2. const [ students, setStudents ] = useState([]);
    3. useEffect(()=>{
    4. (async ()=>{
    5. const stus = await getAllStudents();
    6. setStudents(stus);
    7. })();//useEffect中不能返回一个Promise,所以需要把这个async写为IIFE
    8. }, []);
    9. }
    10. function Test(props){
    11. const stus = useAllStudents();
    12. const list = stus.map(it => <li key={it.id}>it.name</li>);
    13. return (<ul>
    14. {list}
    15. </ul>);
    16. }
    17. export default function App() {
    18. return (
    19. <div>
    20. <Test />
    21. </div>
    22. )
    23. }

    以前类组件呢,倒是也能这样,用高阶组件的的方式,但是太麻烦,而且导致结构层次变深

    1. function willAllStudents(Comp){//传一个组件进来
    2. return class AllStudentsWrapper extends React.Component{
    3. state = {
    4. stus: []
    5. }
    6. async componentDidMount(){
    7. const stus = await getAllStudents();
    8. this.setState({
    9. stus,
    10. })
    11. }
    12. render(){
    13. return <Comp {...this.props} stus={this.state.stus}></Comp>
    14. }
    15. }
    16. }
    17. function Test(props){
    18. const list = props.stus.map(it => <li key={it.id}>it.name</li>);
    19. return (<ul>
    20. {list}
    21. </ul>);
    22. }
    23. const TestStudents = withAllStudents(Test);
    24. export default function App() {
    25. return (
    26. <div>
    27. <TestStudents />
    28. </div>
    29. )
    30. }

    HOOK的出现很好的解决了横向关注点,而且可以很好的拆分纯函数与副作用

    1. 根据页码和页容量获取学生数据,得到一个相应结果,并且页码或页容量变化时,将重新获取学生数据 ```jsx function usePageStudents(page=1, limit=10){ const [resp, setResp] = useState({}); useEffect(()=>{
      1. (async ()=>{
      2. const resp = await getAllStudents(page, limit);
      3. setResp(resp);
      4. })();
      }, [page, limit]); }

    function Test2(){ const [page, setPage] = useState(1); const resp = usePageStudents(page, 10); if(resp){ const list = resp.findByPage.map(it=>

  • {it.name}
  • ) return (

    数据总数:{resp.cont}

      {list}
    { setPage(parseInt(e.target.value, 10)); }} />

    1. );
    2. }else{
    3. return null;
    4. }

    }

    1. 3. 很多组件都需要在第一次加载完成后,启动一个计时器,然后在组件销毁时清除计时器
    2. ```jsx
    3. function useTimer(func, duration){
    4. useEffect(()=>{
    5. const timer = setInterval(func, duration);
    6. return ()=>{
    7. clearInterval(timer);
    8. }
    9. }, []);
    10. }