专栏名称: 前端外刊评论
最新、最前沿的前端资讯,最有深入、最干前端相关的技术译文。
目录
相关文章推荐
商务河北  ·  经开区“美•强•优”三重奏 ·  12 小时前  
前端早读课  ·  【第3453期】圈复杂度在转转前端质量体系中的应用 ·  22 小时前  
奇舞精选  ·  从 DeepSeek 看25年前端的一个小趋势 ·  昨天  
奇舞精选  ·  从 DeepSeek 看25年前端的一个小趋势 ·  昨天  
前端早读课  ·  【第3452期】React 开发中使用开闭原则 ·  昨天  
51好读  ›  专栏  ›  前端外刊评论

React新特性全解(下)

前端外刊评论  · 公众号  · 前端  · 2019-03-25 07:00

正文

感谢 @daisy 的系列投稿!

React 16 新特性全解(上)

前言

这篇文章主要讲Hooks,如果你想了解React 16的其他新特性,请移步 React 16新特性全解 (上), React 16新特性全解 (中)

v16.8 Hooks

Hooks是什么?

我们知道,functional component在使用的时候有一些限制,比如需要生命周期、state的时候就不能用functional component。 而有了Hooks,你就可以在funtional component里,使用class component的功能:props,state,context,refs,和生命周期函数等等。

虽然Hooks已经有要取代正宫class的趋势了,但是react目前没有计划抛弃class,所以不要慌,你还是可以跟往常一样使用class。

在真正介绍Hook之前,还是一样先来了解为什么要引入Hooks?其实不单单是为了给functional component赋于class component的功能。

还有下面的问题:

1.组件之间很难复用逻辑

之前如果我们需要复用逻辑,常用的两种方式是render props 跟 higher-order components。但是这两种方式都需要你重构代码,所以比较麻烦。

最重要的是,用这两种方式的话,在React Devtools里,会看到很多的嵌套组件。

在这个图可以看到Header外层套着很多嵌套组件。

2.复杂组件很难理解

在之前的class component里,我们的生命周期函数里通常放着不相关的代码,而相关的代码确要放在不同的生命周期函数里。这样说可能有点绕,我们来看一个具体的例子。

  1. class App extends React.component {

  2. componentDidMount() {

  3. window.addEventListener('scroll', () => {console.log('a')})

  4. this.fetchData();

  5. }

  6. componentDidUpdate() {

  7. this.fetchData();

  8. }

  9. componentWillUnmount() {

  10. window.removeEventListener('scroll', () => {console.log('a')})

  11. }

  12. render() {

  13. return

    ddddiv>
  14. }

  15. }

  16. 这应该是我们平时会经常写的代码。在componentDidMount里做事件绑定,获取数据。在componentWillUnMount里解绑事件。

    这样做的问题是:componentDidMount装着的代码都是不相关的,而相关联的事件绑定以及事件解绑,分散在componentDidMount 跟 componentWillUnMount里。这样如果组件的逻辑越写越复杂之后,就会变得很难维护易出bug。

    后面讲Effect Hook的时候,我会介绍这个问题用Hooks怎么解决。

    3.class比较难学

    React团队发现class是初学者学习React的大障碍。要学习class component,你必须要知道几点:

    1. this在JS是如何工作的(光是这个就够绕的)

    2. 记得绑定事件

    3. 了解state,props,state以及从上而下的数据流

    4. functional component跟class component的区别,如何使用它们

    如何使用

    理解了Hooks诞生的原因,接着来看看要如何使用。

    假设我需要实现一个功能,点击app时候,count数目加一。用class的形式实现就是 这样的:

    Class:

    1. class Example extends React.Component {

    2. constructor(props) {

    3. super(props);

    4. this.state = {

    5. count: 0

    6. };

    7. }


    8. render() {

    9. return (

    10. You clicked {this.state. count} timesp>

    11. <button onClick={() => this.setState({ count: this.state.count + 1 })}>

    12. Click me

    13. button>

    14. div>

    15. );

    16. }

    17. }

    18. Hooks:

      如果需要用Hooks实现,变成

      1. import React, { useState } from 'react';


      2. function Example() {

      3. // Declare a new state variable, which we'll call "count"

      4. const [count, setCount] = useState(0);


      5. return (

      6. You clicked {count} timesp>

      7. < button onClick={() => setCount(count + 1)}>

      8. Click me

      9. button>

      10. div>

      11. );

      12. }

      13. 演示地址

        在这里demo中。useState就是Hook。我们通过它来在function component里加入state数据。

        两者对比如下:

        1. 定义state变量

        Class:

        1. class Example extends React.Component {

        2. constructor(props) {

        3. super(props);

        4. this.state = {

        5. count: 0

        6. };

        7. }

        Hooks:

        1. import React, { useState } from 'react';


        2. function Example() {

        3. // 通过useState这个Hooks定义state变量:count。并且通过useState给count赋初始值0,只在初始化时候使用一次

        4. const [count, setCount] = useState(0);

        在function component里,我们是没有this的。所以没办法向Class那样用this来创建state,这时候Hooks闪亮登场。

        通过useState这个hooks我们可以定义count这个state变量。 由Hooks定义的state变量不一定要是object,可以是string、number。传入的内容相当于给变量赋初始值。

        1. function ExampleWithManyStates() {

        2. // Declare multiple state variables!

        3. const [age, setAge] = useState(42);

        4. const [fruit, setFruit] = useState('banana');

        5. const [todos, setTodos] = useState([{ text: 'Learn Hooks' }]);

        6. // ...

        7. }

        1. 渲染state

        Class:

        1. You clicked {this.state.count} times

        Hooks:

        1. You clicked {count} times

        可以不需要用this,直接使用count

        3.更新state

        Class:

        1. Click me

        Hooks:

        1. Click me

        我们可以看到 const [count,setCount]=useState(0);useState返回两个参数,一个是当前state的值,还有一个其实是一个函数,用来改变state的值,就是setCount。

        类似setState,但是不同的是,它不会将旧的state跟新的state合并在一起,而是覆盖式的重写state的值。

        说完了functional component里面如何使用state之后,我们再来看如何用Effect Hook来取代生命周期。

        一般我们都会在生命周期componentDidMount, componentDidUpdate与 componentWillUnmount中做一些副作用的操作,例如:获取数据,订阅,手动改变DOM。而在hooks里,这些生命周期函数都被统一成一个方法 useEffect。

        下面我们来举个例子:

        1. import React, { useState, useEffect } from 'react';


        2. function Example() {

        3. const [count, setCount ] = useState(0);


        4. // Similar to componentDidMount and componentDidUpdate:

        5. useEffect(() => {

        6. // Update the document title using the browser API

        7. document.title = `You clicked ${count} times`;

        8. });


        9. return (

        10. You clicked {count} timesp>

        11. <button onClick={() => setCount(count + 1)}>

        12. Click me

        13. button>

        14. div>

        15. );

        16. }

        17. 在这个例子中,我们在useEffect 里完成了副作用的操作。demo演示

          Effects Hooks 就在functional component里, 所以它可以直接访问props跟state。 React在每次render之后都会调用effect,包括第一次render。

          但是这里还遗留两个问题

          1、我们在开篇说到,class component有个问题就是生命周期函数里的代码都是不相关的,而相关的代码确要被打散在不同的生命周期函数里。这个问题用Hooks的话就可以解决。

          比如绑定、解绑事件,在使用class的时候,在componentDidMount里监听了一个事件,之后需要在componentWillMount里给它解绑。

          用Hook只需要在useEffect一个函数就可以做到。它可以通过返回一个函数来专门做清除的工作,代码如下:

          1. import React, { useState, useEffect } from 'react';


          2. function FriendStatus(props) {

          3. const [isOnline, setIsOnline] = useState(null);


          4. function handleStatusChange(status) {

          5. setIsOnline(status.isOnline);

          6. }


          7. useEffect(() => {

          8. ChatAPI







请到「今天看啥」查看全文