React 学习 之 Hooks

171 阅读4分钟

useState

useState 是react 自带的一个hooks函数,它的作用就是用来声明状态变量。useState接收一个参数,即状态初始值;返回一个数组,第[0]项是当前的状态值,第[1]项是改变状态值的方法。

所以我们做的就是声明一个状态变量,设置一个初始值以及改变初始值的方法。

const [count, setCount] = useState(0);
useState接受的初始值并没有规定一定要是什么类型,完全可以接受对象或则数组作为参数。
唯一需要注意的是,之前我们的 this.setState()做的是合并状态后返回一个新的状态,useState是直接替换老状态后返回新的状态,而且无论useState 无论调用多少次,相互之间是独立的。

useState 与 setState差异

在setState只修改state中某个变量的时候,不需要将整个修改后的state传进去:

class Count extends Component {
    constructor(props) {
        super(props);
        this.state = {
            count: 0,
            name: 'snow',
            age: 18
        }
    }    
    handleClick = () => {
        const {count} = this.state;
        // 我们可以只传入修改的某个变量
        this.setState({
            count: count + 1
        })
    }

    render () {
        return (
            <button onClick={this.handleClick}></button>        
        )
    }
}

而使用useState时,我们修改state必须将整个修改后的state传入去,因为它会直接覆盖之前的state,而不是合并之前state。

function Count() {
    const [data, setData] = useState({
        count: 0,
        name: 'snow',
        age: 18,
    })
    
    const handleClick = () => {
        const { count } = data;
        // 这里必须将完整的state对象传进去
        setData({
            ...data,
            count: count + 1,
        })
    }

    return (
        <button onClick={handleClick}></button>
    )
}

react规定必须把hooks写在函数的最外层,不能写在if else 语句当中。

useEffect

我们写的有状态组件,通常会产生很多副作用(side effect),比如,发起ajax请求获取数据,添加一些监听的注册和取消注册,手动修改DOM等等。我们之前都把这些副作用的函数写在生命周期函数钩子里,比如componentDidMount, componentDidUpdate和componentWillUnmount。而现在的useEffect就相当于与这几个生命周期函数钩子的集合体。它以一抵三。

同时,由于前文所说hooks可以反复多次使用,相互独立。所以我们合理的做法是,给每一个副作用一个单独的useEffect钩子。这样一来,这些副作用不再一股脑地堆在生命周期钩子里,代码变得更加清晰。

有两点需要注意

    1)react首次渲染和之后的每次渲染都会调用一遍传给useEffect的函数。而之前我们要用两个生命周期函数来分别表示首次渲染(componentDidMount)和以后更新导致的重新渲染(componentDidUpdate)。
    2)useEffect中定义的副作用函数的执行不会阻碍浏览器更新视图,也就是说这些函数是异步执行的,而之前的componentDidMount和componentDidUpdate中的代码则是同步执行的。

useEffect怎么解绑一些副作用

当我们在componentDidMount里添加了一个注册,我们得马上在componentWillUnmount中,也就是组件被注销之前清除掉我们添加的注册,否则就会出现内存泄漏。
清除方法就是,让我们传给useEffect的副作用函数返回一个新的函数即可。这个新的函数会在组件下一次重新渲染之后执行。
有一点需要注意就是:这种解绑的模式跟componentWillUnmount不一样。componentWillUnmount只会在组件被销毁前执行一次而已。而useEffect里的函数每次组件渲染后都会执行一遍,包括副作用函数里返回的这个清理函数也会重新执行一遍。

怎样跳过一些不必要的副作用函数?

按照之前的思路,每次重新渲染都要执行一遍这些副作用函数,显然是不经济的。怎么跳过一些不必要的计算呢?

我们只需要给useEffect传第二个参数即可。用第二个参数来告诉useEffect只有当这个参数的值发生变化时,才执行我们传的副作用函数(第一个参数)。

useEffect(() => {
    document.title = `You click ${count} times.`;
}, [count]) // 只有当count发生变化时,才会重新执行 `document.title` 这一句
当第二个参数传一个空数组时,其实就相当于只在首次渲染的时候执行。也就是componentDidMount和 componentDidUpdate的模式。不过这种做法可能带来bug,慎用。






参考 

  1. 30分钟精通React Hooks
  2. React hooks实践