美文网首页
React在项目中使用Hooks

React在项目中使用Hooks

作者: 马小帅mm | 来源:发表于2019-03-17 13:52 被阅读0次

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/

相关文章

网友评论

      本文标题:React在项目中使用Hooks

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