https://react.docschina.org/docs/getting-started.html

之前跟大家说过,react文档最重要的是理解这两部分的内容(高级指引部分有时间最好过一遍)。

对于已经掌握过vue知识的人来说,核心概念会较好理解,这篇文章主要是帮助大家理解Hook章节的内容。

image.png

从没有hooks说起

在没有hooks之前,react的组件有两种:函数组件,类组件

  1. function Welcome(props) {
  2. return <h1>Hello, {props.name}</h1>;
  3. }
  1. class Welcome extends React.Component {
  2. render() {
  3. return <h1>Hello, {this.props.name}</h1>;
  4. }
  5. }

相比较函数式组件,类组件存在两个函数组件没有的东西

  1. 状态
  2. 生命周期 ```javascript class Clock extends React.Component { constructor(props) { super(props); this.state = {date: new Date()}; }

    componentDidMount() { this.timerID = setInterval( () => this.tick(), 1000 ); }

    componentWillUnmount() { clearInterval(this.timerID); }

    tick() { this.setState({ date: new Date() }); }

    render() { return (

    1. <h1>Hello, world!</h1>
    2. <h2>It is {this.state.date.toLocaleTimeString()}.</h2>

    ); } }

ReactDOM.render( , document.getElementById(‘root’) );

  1. 查看以上代码,其中 this.state属于状态,它与ui界面息息相关,可以看作Vue中的data,属于数据模型对UI界面的一种映射;其中componentDidMountcomponentWillUnmount属于生命周期钩子函数,需要在特定的页面周期才会触发的函数
  2. 思考一下一个问题:缺少了状态和生命周期,我们只能做什么样的组件?
  3. 答案是:纯组件,或者叫无状态组件,这种组件定义类似于纯函数。
  4. 纯函数
  5. > - 它应始终返回相同的值。不管调用该函数多少次,无论今天、明天还是将来某个时候调用它。
  6. > - 自包含(不使用全局变量)。
  7. > - 它不应修改程序的状态或引起副作用(修改全局变量)。
  8. 以上来自于网络上对于纯函数的定义,简单来理解就是:输出仅因输入改变,与外部时间等其他因素无关的函数;如 y=f(x), y的值仅根据x改变,与调用时间,调用方式无关。
  9. 因此纯组件也就比较好理解了,一个简单的例子就是一个显示文字的组件,它显示的文字由props传入,不管何时何地调用,组件仅与props参数有关。
  10. 但是我们可以看到,几乎所有的页面级组件(也叫容器组件)都是需要生命周期和状态的,不然无法应对复杂的业务环境。
  11. 因此,在hooks未出现之前,类组件才是react的主流组件。
  12. <a name="lzlry"></a>
  13. ### hooks带来了什么
  14. [https://react.html.cn/docs/hooks-intro.html](https://react.html.cn/docs/hooks-intro.html)<br />[https://react.html.cn/docs/hooks-overview.html](https://react.html.cn/docs/hooks-overview.html)
  15. 以上两个链接属于官方解释什么是hooks以及为什么要引入hooks,这里不再赘述,我仅仅只介绍两个最常用的hooksuseStateuseEffect,并且从中分析hooks带来的好处。
  16. ```javascript
  17. import { useState, useEffect } from 'react';
  18. function Example() {
  19. const [count, setCount] = useState(0);
  20. // 这里类比 this.state = { count: 0 }
  21. // this.setState({ count: xxx})
  22. useEffect(() => {
  23. document.title = `You clicked ${count} times`;
  24. });
  25. // 默认情况下,效果在每次完成渲染后运行,一种副作用hooks
  26. return (
  27. <div>
  28. <p>You clicked {count} times</p>
  29. <button onClick={() => setCount(count + 1)}>
  30. Click me
  31. </button>
  32. </div>
  33. );
  34. }

可以看到,useState比较好理解,相当于为函数组件引入了状态,不过需要注意

  1. const [count, setCount] = useState(0);
  2. // useState(0) 代表初始值为0,返回count为 state 变量,
  3. // setCount为修改函数,必须要要用这个函数进行修改,不然无法触发ui更新

useEffect, effect在英文中的意思是副作用,那么什么是副作用呢?

还记得之前提到的纯组件吗?纯组件中,所有的逻辑应该是与时间状态无关的,但是很显然,为了实现类似于生命周期的效果,我们不得不违背这个原则,useEffect则是在这个背景下应运而生的函数。

  1. useEffect(() => {}); 仅传入一个函数,则默认组件每次渲染都会运行一次
  2. useEffect(() => {
  3. const subscription = props.source.subscribe();
  4. return () => {
  5. // Clean up the subscription
  6. subscription.unsubscribe();
  7. };
  8. });
  9. // 在函数中return一个函数,意味着在组件卸载时会运行这个函数,类似于componentWillUnMount
  10. useEffect(
  11. () => {
  12. const subscription = source.subscribe();
  13. return () => {
  14. subscription.unsubscribe();
  15. };
  16. },
  17. [source],
  18. );
  19. // 传入第二个参数source,意味着source每次变化都会导致第一个参数中的函数重新运行一次
  20. useEffect(() => {
  21. ChatAPI.subscribeToFriendStatus(props.friend.id, handleStatusChange);
  22. return () => {
  23. ChatAPI.unsubscribeFromFriendStatus(props.friend.id, handleStatusChange);
  24. };
  25. }, []);
  26. // 传入第二个参数为一个空数组,意味着此函数只会运行一次,return的函数则在卸载时运行一次,
  27. // 类似于componentDidMount 和 componentWillUnmount

可以发现,利用useEffect可以实现比生命周期函数更灵活的功能,如,依赖于某个或多个变量变化而触发的effect,对于同一个副作用不用分割在不同的生命周期函数。

更多

hooks除了useState,useEffect之外,还有很多其他api,官方文档如下:

https://react.html.cn/docs/hooks-reference.html
image.png

如何练习

参考:https://www.yuque.com/ironknt/ptxgfr/sv5zmt
运行一个ant design pro demo,里面的页面都是依赖于hook的函数组件,可以尝试阅读,修改,模仿来更好的学习hook的使用