React useEffect

今早来又莫名其妙的遇到了 bug,排查了一下是 useEffect 导致的。今天就再来详细的学习一下 react useEffect。

为什么要?

我们知道,react 的函数组件里面没有生命周期的,也没有 state,没有 state 可以用 useState 来替代,那么生命周期呢?

useEffect 是 react v16.8 新引入的特性。我们可以把 useEffect hook 看作是componentDidMount、componentDidUpdate、componentWillUnmounrt三个函数的组合。

详解

原来我们是这么写 class component

class LifeCycle extends React.Component {
	constructor(props) {
    super(props);
    this.state = {
      count: 0
    };
  }
  componentDidMount() {
    document.title = `you clicked me ${this.state.count} times`;
  }
  componentDidUpdate() {
    document.title = `you clicked me ${this.state.count} times`
  }
  render() {
    return (
      <div>
        <p>You clicked {this.state.count} times</p>
        <button onClick={()=> this.setState({count: this.state.count + 1})}>
        	Click me
        </button>
      </div>
    )
  }
}

现在我们使用 hook 来写 function component

import React, { useState, useEffect } from 'react';
function Example() {
	const [count, setCount] = useState(0);
	useEffect(() => {
		document.title = `you clicked ${count} times`;
	})
	return (
		<div>
			<p>You clicked {count} times</p>
			<button onClick={() => setCount(count + 1)}
				Click me
			</button>
		</div>
	)
}

上面的这段代码,每次 count 变更以后,effect都会重新执行。

我们日常开发中,获取数据、订阅以及手工更改 React 组件中的 DOM(我之前就更改过)都属于副作用。有些副作用可能需要清除,所以需要返回一个函数,比如设置定时器、清除定时器。

class Example extends Component {
	constructor(props) {
		super(props);
		this.state = {
			count: 0;
		}
	}
	componentDidMount() {
		this.id = setInterval(() => {
			this.setState({count: this.state.count + 1})
		}, 1000)
	}
	componentWillUnmount() {
		clearInterval(this.id)
	}
	render() {
		return <h1>{this.state.count}</h1>;
	}
}

使用 Hook 的示例

function Example() {
	const [count, setCount] = useState(0);
	useEffect(() => {
		const id = setInterval(() => {
			setCount(c => c + 1);
		}, 1000);
		return () => clearInterval(id);
	}, []);
	return <h1>{count}</h1>
}

我们可以让 React 跳过对 effect 的调用,让 effect 的执行依赖于某个参数(传利数组作为 useEffect 的第二个可选参数就可以了)。倘若仅仅只想执行一次,那么就传递一个空的数组作为第二个参数,这个时候 useEffect hook 不依赖于 props 或者任何值,所以永远都不重复执行。

在过去的性能优化里,在某些情况下,每次渲染后都执行清理或者执行 effect 都可能会导致性能的问题。在 class 组件中,我们通过在 componentDidUpdate 添加 prevProps或者 prevState 来解决。

componentDidUpdate(prevProps, prevState) {
	if(prevState.count !== this.state.count) {
		document.title = `You clicked ${this.state.count} times`
	}
}

这个是非常常见的需求。而如今,倘若我们使用 function component,代码会非常的简洁。

useEffect(() => {
	document.title = `You clicked ${count} times`;
}, [count])

总结

Hook 是对函数式组件的一次增强,v16.8 出现以后才出来的 hook 特性。在这之前,我看有的代码里面,通过一个<InitialCallBack>来放到函数时组件的最前面,通过在<InitialCallBack>的 componentDidMount 来获取后端接口数据。

就是变相的往 Hook 里面引入生命周期。

然而 v16.8 出来了,这个问题完全解决了。

Hook的语法更简洁易懂,消除了 class 的声明周期方法导致的重复逻辑代码。

同时,在某种程度上解决了高阶组件难以理解和使用的问题。

然而 Hook 并没有让函数时组件做到 class 组件做不到的事情,只是让很多组件变得写的更简单。class 组件不会消失,hook 化的函数时组件将是趋势。

原文地址:https://www.cnblogs.com/ssaylo/p/13272166.html