在 React 的 Class 组件中,常出现相关业务逻辑代码散在 componentDidMount, componentWillUpdate, componentWillUnmount 等生命周期函数中的情况。这样的代码可维护性差。查找或更改这块逻辑时,都要找多个地方。

解决方案

Hook 是 React 16.8 的新增特性。用 React 的 Hooks 可以优雅的聚集零散业务代码。React Hooks 通过 useState,useEffect 来聚集代码。

我们来看个 Demo。实现:浏览器窗口的大小变化时,将值传给服务器端。

Class 组件的写法:

  1. class Demo extends React.Component {
  2. constructor(props) {
  3. super(props)
  4. this.state = {
  5. windowSize: {
  6. width: window.innerWidth,
  7. height: window.innerHeight
  8. }
  9. }
  10. }
  11. componentDidMount() {
  12. window.addEventListener('resize', this.handleResize);
  13. }
  14. componentWillUnmount() {
  15. window.removeEventListener('resize', this.handleResize)
  16. }
  17. handleResize = () => {
  18. this.setState({
  19. windowSize: {
  20. width: window.innerWidth,
  21. height: window.innerHeight
  22. }
  23. }, () => this.report())
  24. }
  25. // 将值传给服务器端
  26. report(windowSize) {
  27. console.log(`report windowSize: ${windowSize}`)
  28. }
  29. }

业务逻辑代码散在 会散在 componentDidMount,componentWillUnmount, handleResize 和 report 这 4 个地方。

用 Hook 的写法,可以将业务逻辑聚在一处,如下:

  1. function Demo() {
  2. const [windowSize, setWindowSize] = useState([
  3. window.innerWidth,
  4. window.innerHeight
  5. ]);
  6. useEffect(() => {
  7. // 组件 mount 后执行。
  8. const handleResize = () => {
  9. setWindowSize([window.innerWidth, window.innerHeight]);
  10. }
  11. window.addEventListener('resize', handleResize);
  12. // return 的函数在组件 unmount 后触发。
  13. return () => window.removeEventListener('resize', handleResize);
  14. }, []);
  15. // 将值传给服务器端
  16. const report = (windowSize) {
  17. console.log(`report windowSize: ${windowSize}`)
  18. }
  19. // 浏览器窗口值变化后触发。
  20. useEffect(report, [windowSize]);

为了复用监听浏览器窗口大小的逻辑,可以将这段业务抽象成自定义 Hook,如下:

  1. import {useState, useEffect} from 'react'
  2. export default function useWindowResize(callback) {
  3. const [windowSize, setWindowSize] = useState([
  4. window.innerWidth,
  5. window.innerHeight
  6. ]);
  7. useEffect(() => {
  8. const handleResize = () => {
  9. setWindowSize([window.innerWidth, window.innerHeight]);
  10. }
  11. window.addEventListener('resize', handleResize);
  12. return () => window.removeEventListener('resize', handleResize);
  13. }, []);
  14. useEffect(callback, [windowSize]);
  15. }

使用:

  1. const windowSize = useWindowSize(report)
  2. // 将值传给服务器端
  3. const report = (windowSize) {
  4. console.log(`report windowSize: ${windowSize}`)
  5. }
  6. useEffect(report, [windowSize]);

代码是不是变得很内聚,用 Hook 来重构零散的代码吧~

参考文档