10 分钟了解 Hooks API

作者: 写代码的海怪 | 来源:发表于2018-12-21 06:53 被阅读74次

Hooks API 是 React 16.7.0-alpha.0 版本推出的 API,要注意的是只有这个版本才有,别的版本都没有,如果你在 16.7.0 正式版是没有的!我就是被坑了。

如果你用 create-react-app 来创建应用的,现在的版本会是 16.7.0,一定要改成 16.7.0-alpha.0 才能使用 Hooks API

useState

useState API 本质了为了使得函数式组件也能有自身状态而推出的 API。

以前的函数组件

假如我们要做一个简单的计数器,如果用以前的函数式组件是不行的,因为函数式组件是没有自身状态的。比如:

function App()l {
  let count = 0
  let add = function() {}
  return (
    <div>
      <div>{count}</div>
      <div><button onClick={add}>+1</button></div>
    </div>
   )
}

你可能说 count 不行么?因为每次 render 的时候这个函数就会被执行一次,那么就会执行 let count = 0 ,所以每次都会重置了 count,没用。

解决方法是用 class 组件,在 this.state 对象里放入 count

class App extends React.Component {
    constructor(props) {
        super(props)
        this.state = {
            count: 0
        }
    }

    add = () => {
        this.setState({
            count: this.state + 1
        })
    }

    render() {
        return (
          <div>
            <div>App: {count}</div>
            <div>
              <button onClick={add}>+1</button>
            </div>
          </div>
        )
    }
}

烦不烦?写那么多个单词。所以 Hooks API 出现了,它可以给函数式组件拥有自身状态。

使用 useState

useState 的作用就是创建一个状态,可以是对象也可以是别的类型,还会创建一个修改这个状态的函数。上面的例子用新 API 可以写成这样:

function App() {
    // 状态和修改状态的函数
    const [count, setCount] = useState(0)

    // Handler
    const add = () => {
        setCount(count + 1)
    }

    return (
      <div>
        <div>App: {count}</div>
        <div>
          <button onClick={add}>+1</button>
        </div>
      </div>
    )
}

是不是感觉清爽很多了?没有什么 constructor, super, render 那么多东西,现在只需要我好好写一个函数就行了。

注意

  • 不能在函数式组件外面使用 useState,这个很好理解,毕竟定义的就是自己的状态当然在组件自己里使用
  • 数组里的名字可以改,可以是 const [x, y] = useState(0),你自己清楚 x, y 代表什么就好了

useEffects

这个 API 就有点难理解了,Effect 的翻译是影响,副作用。这里的 Effects,相当于你使用了别人的东西。

什么是 Effect

这里的 Effect 分两种:一种叫 Effects without Cleanup,就是说你拿别人的东西吃,吃完这个东西就没了,不用再去清理,因为东西就在你肚子里呀。另一种叫 Effects with Cleanup,比如你拿别人的书看,看完了还得将书要么扔了,要么还给别人,总之这本书你得处理。

那么 React Effects 有哪些呢?简单的如:DOM 修改,网络请求,订阅事件,这些都是使用了组件之外的资源,所以每一次的这些行为就是一个 Effect。

那为毛要搞一个 useEffects 呢?下面就分两种 Effects 情况来说说吧,同时讲下怎么使用 useEffects。

Effects with Cleanup

想像一个场景,每次更新 count 之后都要设置 document.title = count,你会怎么做。哎,这个简单,在上面的 add() 函数里直接改不就好了?但是假如这个 count 作为共享数据可以被所有组件修改的,而且有 minus(), divide(), multiple() 等方法去改这个值,那就要重复很多次 document.title = count

这时候我们可以总结出不管怎样去修改,反正就是修改后就要执行 document.title = count 代码嘛。即然是 count 值每次都修改就会导致这个组件重新渲染,那么那我在生命钩子componentDidUpdatecomponentDidMount 里去改 title不就好了?如:

class App extends React.Component {
    constructor(props) {
        super(props)
        this.state = { count: 0 }
    }

    componentDidMount() {
        document.title = this.state.count
    }
    componentDidUpdate() {
        document.title = this.state.count
    }
    
    render() {
        return (...)
    }
}

还是那个问题:烦不烦啊,还要我写两次。这时候 React 就推出了 useEffect,即每次渲染(包括 mounted 和 updated)后,即就是说每次执行 render 后,会回调一个函数,这个函数执行你要做的事情。

可以将上面的改写成这样。

function App (props) {
    useEffect(() => {
        document.title = count
    })
    return (...)
}

代码变成6行,舒服~。再回来看看 Effect 的定义,使用组件外的东西,对呀我们使用了 document 对象,这不是组件里的呀。好像也不太需要清理什么东西,因为就设置一个值嘛。所以这就叫 Effects without Cleanup。

Effects with Cleanup

有 without 就有 with,什么时候要 Cleanup 呢?那肯定是无端端创建东西的时候嘛,像垃圾回收一样,如果创建的东西不再需要了,那就清掉呗。React 里的例子是添加监听事件喽。

比如在一个 MyButton 组件开始的时候我要默认添加一个事件中心的监听回调,然后这个组件销毁的时候回收这个回调函数。使用生命钩子会写成这样:

class MyButton extends React.Component {
    constructor(props) {
        super(props)
        this.state = { isTriggered: false }
    }

    componentDidMount() {
        EventHub.on('Trigger event', this.state.isTriggered, () => {
            console.log('Do something')
        })
    }
    componentWillUnmount() {
        EventHub.removeListener('Trigger event', this.state.isTriggered, () => {
            console..log('Listener is removed')
        })
    }
    render() {
        return ( ... )
    }
}

我们使用了 EventHub,很明显这不是组件里的东西,是属性外面的,所以这也是个 Effect。
而这次使用 useEffect 就不太一样了,因为我们是要擦屁股的,在组件 unmount 的时候取消监听。而 useEffect 提供了一个很好理解的用法。

function MyButton(props) {
    useEffect(() => {
        EventHub.on('Trigger event', this.state.isTriggered, () => {
            console.log('Do something')
        })

        return function cleanup() {
            EventHub.removeListener('Trigger event', this.state.isTriggered, () => {
                console.log('listener is removed')
            })
        }
    })
    return (...)
}

当组件 unmount 的时候就会去执行 cleanup 这个函数,是不是感觉一目了然?这里的函数名不是必须的,只是为了说明这里用来清理而已。

注意

  1. 代码简洁就不用说太多了,一看就知道谁好用了
  2. 而因为使用生命钩子是同步的,会阻塞页面的渲染,或者组件的销毁也会造成页面卡顿。而 setEffect 里面其实是异步进行的不会有这些影响
  3. 当然 setEffect 也不是全都是好的,比如每次 render 后都会用一个一模一样的函数去替换原来来的回调,以保持状态都是最新的

当然这只是简单的用法,更多的用法请看官方文档

相关文章

  • 10 分钟了解 Hooks API

    Hooks API 是 React 16.7.0-alpha.0 版本推出的 API,要注意的是只有这个版本才有,...

  • React Hooks 入门

    目录 什么是 React Hooks? 为什么要创造 Hooks? Hooks API 一览 Hooks 使用规则...

  • react hooks 学习记录

    Hooks Api 索引 基础 Api useStateuseEffectuseContext返回一个 state...

  • Hooks API

    useEffect useEffect的使用 参考上篇文章 执行时机: useEffect可以看做componen...

  • React Hooks 入门

    React Hooks 是 React v16.8 版本引入了全新的 API。 React Hooks 基本概念 ...

  • 优化前端工作流:一、使用husky对commit日志校验

    Git Hooks 在了解husky之前,我们需要先了解一下Git Hooks。Git Hooks是git提供的一...

  • 剖析React Hooks底层源码

    Hooks API 类型 据官方声明,hooks 是完全向后兼容的,class componet 不会被移除,作为...

  • react-hooks

    react-hooks react-hooks 是react16.8以后,react新增的钩子API,目的是增加代...

  • React Hooks API

    1. useState 等价于 复杂的state 注意:useState只能放在函数组件内部,不能单独拿出来 2....

  • 【React】Hooks API

    参考链接【https://reactjs.org/docs/hooks-intro.html】【https://m...

网友评论

    本文标题:10 分钟了解 Hooks API

    本文链接:https://www.haomeiwen.com/subject/pwupkqtx.html