React在项目中使用Hooks

Hooks是React 16.8中的新增功能。它们允许您在不编写类class的情况下使用状态state和其他React功能。
要使用Hooks请先升级你的React包,包括ReactDom

为什么使用Hooks

我们总是会遇到某些困惑,比如:

  • 当我们定义的一个组件只用到一两个state状态变量
  • 一个组件只用到用到了生命周期某一个方法例如componentDidMountcomponentWillUpdatecomponentWillMount

为了解决上面的问题,我们不得不定义一个class component,来达到我们的目的,看起来代码有很多的冗余。而hooks就是帮我们解决这些问题,让我们可以抛弃class component拥抱function component,使代码看起来清晰,整洁。

如何使用useState

引用官方的一个例子:

import React, { useState } from 'react';

function Example() {
  // Declare a new state variable, which we'll call "count"
  const [count, setCount] = useState(0);

  return (
    <div>
      <p>You clicked {count} times</p>
      <button onClick={() => setCount(count + 1)}>
        Click me
      </button>
    </div>
  );
}

看一下上面做了什么操作:

  1. 定义了一个名称为Examplefunction component
  2. 使用useState在这个方法内部定义了一个变量count
  3. 并暴露了一个修改count的方法setCount
  4. 每次点击按钮对count递增

如果我们用class component是如何实现上面的步骤的呢?等效于:

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

  render() {
    return (
      <div>
        <p>You clicked {this.state.count} times</p>
        <button onClick={() => this.setState({ count: this.state.count + 1 })}>
          Click me
        </button>
      </div>
    );
  }
}

一对比我们会发现使用Hooks能让代码看起来更加有条理,简洁,也能使状态和UI层分离
当然Hooks能让我们可以定义多个状态,每个状态都是独立的

function ExampleWithManyStates() {
  // Declare multiple state variables!
  const [age, setAge] = useState(42);
  const [fruit, setFruit] = useState('banana');
  const [todos, setTodos] = useState([{ text: 'Learn Hooks' }]);

同时我们会想到如果有很多个状态,我们要写多个useStateHooks支持状态值是对象,我们也可以这样写:

  const [data, setData] = useState({age: 42, fruit: 'banana', todos: [{ text: 'Learn Hooks' }]});

需要注意的是,上面的方括号[data, setData]并不是Hooks的语法,而是JavaScript数组结构

如何使用useEffect

我们常常需要在组件加载的时候就需要运行某些函数,异步请求数据,我们可能会这样写:

import { Component } from 'react';
import axios from 'axios'

class Exampel extends Component {
  constructor(props) {
    super(props);
     this.state = {
       data: null
     };
  }
 
 getItem = () => {
    axios
      .post('请求url')
      .then(res => {
         this.setState{
           data: res.data
         }
      })
      .catch(err => console.error(err))
  }

  componentDidMount () {
    this.getItem()
  }

  //...
}

使用HooksuseEffect我们可以这样写:

import { useState, useEffect } from 'react'
import axios from 'axios'

function Example(){
  const [data, setData] = useState([]);

  function getItem () {
    axios
      .post('请求url')
      .then(res => {
       setData(res.data)
      })
      .catch(err => console.error(err))
  }

  useEffect(() => {
    getItem()
  }, [])

  //...
}

当然我开始也是这样写的,毫无疑问这样写目前看起来没有什么问题,能达到预期的效果。
但是有时候我会发现使用useEffect的时候,里面的函数被无限循环调用了,这当然和我想象的初始化的时候只执行一次出入很大,这是为什么呢?
我们来看个例子:
在发送请求的时候,往往我们会添加一些参数:

import { useState, useEffect } from 'react'
import axios from 'axios'

function Example(){
  const [data, setData] = useState([]);
  const [params, setParams] = useState({});

  function getItem () {
    axios
      .post('请求url', params) //注意我在这里使用了另一个状态params
      .then(res => {
       setData(res.data)
      }) 
      .catch(err => console.error(err))
  }

  useEffect(() => {
    getItem()
  }, [getItem]) //在参数改变的时候调用

  //...
}

上面的例子,我在useEffect 里的依赖函数getItem又对返回函数data赋值,使得每次data改变的时候useEffect就会被触发,导致了无限循环。
解决方法就是把useEffect的第二个参数改成[]也就是useEffect(() => {....}, []),这意味着效果函数应该被调用一次:仅在第一次装载/渲染之后。但是这并不符合Hooks规范。或者是你要的效果就是params改变后再次调用请求,用useCallback看看能否解决问题。

import { useState, useEffect, useCallback } from 'react'
import axios from 'axios'

function Example(){
  const [data, setData] = useState([]);
  const [params, setParams] = useState({});

  const getItem = useCallback(() => { //使用useCallback解决依赖函数的不可控变量
    axios
      .post('请求url', params) //注意我在这里使用了另一个状态params
      .then(res => {
       setData(res.data)
      }) 
      .catch(err => console.error(err))
  }, [params, setData])//在useCallback里检查变量的改变

  useEffect(() => {
    getItem()
  }, [getItem]) //符合useEffect规范

  //...
}

我们推荐使用上面这种方法解决避免useEffect无限循环
无限循环调用产生的原因主要有以下几种,你可以一个个排除看看:

  1. 是不是在依赖函数里重新设置了状态
  2. 是什么操作引起了父组件重新render,导致本身组件也被重新加载,引起无限循环
  3. useEffect是不是被放在了判断if语句或者循环for语句里面了
    当然我们还这样使用:
useEffect(() => {
    function getItem () {
      axios
        .post('https://www.easy-mock.com/mock/5b4eb12d56c59c6f56266215/api/order_list', params) // 注意我在这里使用了另一个状态params
        .then(res => {
          setData(res.data)
        })
        .catch(err => console.error(err))
    }
    getItem()
  }, [params, setData])

useEffect所有依赖的函数放在useEffect里面,让useEffect变得自给自足,这样我们减少了很多不可控制的因素,方法里面所有的依赖项都是可见的可控的。
还有一些Hooks提供的方法useRefuseCallback等好用的方法可以查看官网API https://reactjs.org/docs/hooks-reference.html

总结:使用Hooks的好处:

  1. 可以让我们放弃class component ,拥抱function component
  2. 可以在function component使用状态且是独立的状态,可以独立维护,这和状态组件有着很大的区别
  3. 可以让我们一个个组件去做优化,不需要全部重构
  4. 使状态与UI分离
  5. 让我们的代码看起来更加有条理、清晰、简洁

tips: 简书上交流可能会看不到消息,如有问题,欢迎进群交流50063010
参考链接1:https://reactjs.org/docs/hooks-intro.html
参考链接2:https://overreacted.io/a-complete-guide-to-useeffect/

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 211,194评论 6 490
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,058评论 2 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 156,780评论 0 346
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,388评论 1 283
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,430评论 5 384
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,764评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,907评论 3 406
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,679评论 0 266
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,122评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,459评论 2 325
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,605评论 1 340
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,270评论 4 329
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,867评论 3 312
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,734评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,961评论 1 265
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,297评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,472评论 2 348