理想论坛_专业20年的财经股票炒股论坛交流社区 - 股票论坛

 找回密码
 立即注册
搜索
热搜: 活动 交友 discuz
查看: 2925|回复: 0

关于为什么使用React新特性Hook的一些实践与浅见

[复制链接]

9650

主题

9650

帖子

2万

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
28966
发表于 2019-12-27 13:44 | 显示全部楼层 |阅读模式
前言

关于Hook的界说官方文档是这么说的:
  1. Hook 是 React 16.8 的新增特征。它可以让你在不编写 class 的情况下利用 state 以及其他的 React 特征。
复制代码
简单来说,就是在利用函数式组件时能用上state,还有一些生命周期函数等其他的特征。
假如想了解Hook怎样用,官方文档和阮一峰的React Hooks 入门教程都讲得很清楚了,我倡议间接看官方文档和阮大神的文章即可。
本篇博客只讲为什么要用React的Hook新特征,以及它治理了什么题目。
为什么利用Hook?

让我们先看看他人怎样说。
阮大神的文章中给了一个示例代码:
  1. import React, { Component } from "react";export default class Button extends Component {  constructor() {    super();    this.state = { buttonText: "Click me, please" };    this.handleClick = this.handleClick.bind(this);  }  handleClick() {    this.setState(() => {      return { buttonText: "Thanks, been clicked!" };    });  }  render() {    const { buttonText } = this.state;    return {buttonText};  }}
复制代码
而且提出:
  1. 这个组件类仅仅是一个按钮,但可以看到,它的代码已经很"重"了。实在的 React App 由多个类依照层级,一层层组成,复杂度成倍增加。再加入 Redux,就变得更复杂。
复制代码
现实上,上面这个代码的“重”有部分根源于写法题目,他大要并没有“重”,让我们看看下面这类class写法:
  1. import React, { Component } from "react";export default class Button extends Component {  state = {    buttonText: "Click me, please"  }  handleClick = () => {    this.setState(() => {      return { buttonText: "Thanks, been clicked!" };    });  }  render() {    const { buttonText } = this.state;    return {buttonText};  }}
复制代码
然后再对照下利用了Hook的函数式组件:
  1. import React, { useState } from "react";export default function Button() {  const [buttonText, setButtonText] = useState("Click me,   please");  function handleClick() {    return setButtonText("Thanks, been clicked!");  }  return {buttonText};}
复制代码
即使是我们简化过的class写法,比起Hook的看起来似乎也确切“重”了点。
Hook的语法确切简便了一些,可是这个出处并不是那末充实。
阮大神同时罗列了Redux 的作者 Dan Abramov 总结了组件类的几个弱点:

  • 大型组件很难拆分和重构,也很难测试。
  • 营业逻辑分离在组件的各个方式当中,致使反复逻辑或关联逻辑。(这里我以为阮大神写的大要有点题目,应当是是各个生命周期方式更加正确)
  • 组件类引入了复杂的编程形式,比如 render props 和高阶组件。
这三点都是究竟,因而有了函数化的组件,但之前的函数化组件没有state和生命周期,有了Hook那末便可以治理这个痛点。
而且Hook并不可是这么简单,经过自界说Hook,我们可以将原有组件的逻辑提取出来实现复用。
用useEffect治理生命周期致使的反复逻辑或关联逻辑

上面举的几个弱点,第一点和第三点你大要很轻易大白,第二点就不轻易大白了,所以我们需要深入到具体的代码中去大白这句话。
我们看看下面这段代码:
  1. import React, { Component } from "react";export default class Match extends Component {  state={    matchInfo:''  }  componentDidMount() {    this.getMatchInfo(this.props.matchId)  }  componentDidUpdate(prevProps) {    if (prevProps.matchId !== this.props.matchId) {      this.getMatchInfo(this.props.matchId)    }  }  getMatchInfo = (matchId) => {    // 请求背景接口获得赛事信息    // ...    this.setState({      matchInfo:serverResult // serverResult是背景接口的返回值    })  }  render() {    const { matchInfo } = this.state    return {matchInfo}
  2. ;  }}
复制代码
这样的代码在我们的营业中经常会出现,经过点窜传入赛事组件的ID,去改变这个赛事组件的信息。
在上面的代码中,受生命周期影响,我们需要在加载终了和Id更新时都写上反复的逻辑和关联逻辑。
所以现在你应当比力好大白这句话:营业逻辑分离在组件的各个生命周期方式当中,致使反复逻辑或关联逻辑
为了处理这一点,React供给了useEffect这个钩子。
可是在讲这个之前,我们需要先了解到React带来的一个新的脑筋:同步。
我们在上面的代码中所做的现实上就是在把组件内的状态和组件外的状态举行同步。
所以在利用Hook之前,我们需要先摒弃生命周期的脑筋,而用同步的脑筋去思考这个题目。
现在再让我们看看革新后的代码:
  1. import React, { Component } from "react";export default function Match({matchId}) {  const [ matchInfo, setMatchInfo ] = React.useState('')  React.useEffect(() => {    // 请求背景接口获得赛事信息    // ...    setMatchInfo(serverResult) // serverResult是背景接口的返回值  }, [matchId])    return {matchInfo}
  2. ;}
复制代码
看到这个代码,再对照上面的代码,你心中第一反应应当就是:简单。
React.useEffect继续两个参数,第一个参数是Effect函数,第二个参数是一个数组。
组件加载的时候,实行Effect函数。
组件更新会去判定数组中的各个值能否变更,假如稳定,那末不会实行Effect函数。
而假如不传第二个参数,那末不管加载照旧更新,城市实行Effect函数。
顺便提一句,这里有组件加载和更新的生命周期的概念了,那末也应当是有组件卸载的概念的:
  1. import React, { Component } from "react";export default function Match({matchId}) {  const [ matchInfo, setMatchInfo ] = React.useState('')  React.useEffect(() => {    // 请求背景接口获得赛事信息    // ...    setMatchInfo(serverResult) // serverResult是背景接口的返回值    return ()=>{      // 组件卸载后的实行代码    }  }, [matchId])    return {matchInfo}
  2. ;}}
复制代码
这个常用于事变绑定解绑之类的。
用自界说Hook治理高阶组件

React的高阶组件是用来提炼反复逻辑的组件工场,简单一点来说就是个函数,输入参数为组件A,输出的是带有某逻辑的组件A+。
回想一下上面的Match组件,假如这个组件是页面A的首页头部用来展现赛事信息,然后现在页面B的侧边栏也需要展现赛事信息。
题目就在于页面A的这块UI需要用div,而页面B侧边栏的这块UI需要用到span。
保证本日早点放工的做法是复制A页面的代码到页面B,然后改下render的UI即可。
保证今后早点放工的做法是利用高阶组件,请看下面的代码:
  1. import React from "react";function hocMatch(Component) {  return class Match React.Component {    componentDidMount() {      this.getMatchInfo(this.props.matchId)    }    componentDidUpdate(prevProps) {      if (prevProps.matchId !== this.props.matchId) {        this.getMatchInfo(this.props.matchId)      }    }    getMatchInfo = (matchId) => {      // 请求背景接口获得赛事信息    }    render () {      return (              )    }  }}const MatchDiv=hocMatch(DivUIComponent)const MatchSpan=hocMatch(SpanUIComponent)
复制代码
可是现实上有的时候我们的高阶组件大要会更复杂,比如react-redux的connect,这就是高阶组件的复杂化利用方式。
又比如:
  1. hocPage(  hocMatch(    hocDiv(DivComponent)  ))
复制代码
毫无疑问高阶组件能让我们复用很多逻辑,可是过于复杂的高阶组件会让以后的保护者望而生畏。
而Hook的玩法是利用自界说Hook去提炼这些逻辑,首先看看我们之前利用了Hook的函数式组件:
  1. import React, { Component } from "react";export default function Match({matchId}) {  const [ matchInfo, setMatchInfo ] = React.useState('')  React.useEffect(() => {    // 请求背景接口获得赛事信息    // ...    setMatchInfo(serverResult) // serverResult是背景接口的返回值  }, [matchId])    return {matchInfo}
  2. ;}
复制代码
然后,自界说Hook:
  1. function useMatch(matchId){  const [ matchInfo, setMatchInfo ] = React.useState('')  React.useEffect(() => {    // 请求背景接口获得赛事信息    // ...    setMatchInfo(serverResult) // serverResult是背景接口的返回值  }, [matchId])  return [matchInfo]}
复制代码
接下来,点窜本来的Match组件
  1. export default function Match({matchId}) {  const [matchInfo]=useMatch(matchId)  return {matchInfo}
  2. ;}
复制代码
相比高阶组件,自界说Hook加倍简单,也加倍轻易大白。
现在我们再来处置赏罚以下这类情况:
  1. hocPage(  hocMatch(    hocDiv(DivComponent)  ))
复制代码
我们的代码将不会出现这类不停嵌套情况,而是会酿成下面这类:
  1. export default function PageA({matchId}) {  const [pageInfo]=usePage(pageId)  const [matchInfo]=useMatch(matchId)  const [divInfo]=useDiv(divId)  return
  2. [list]   
  3. [*]{pageInfo}   
  4. [*]{matchInfo}   
  5. [*]{divInfo}  
  6. [/list]}
复制代码
能否需要革新旧的class组件?

现在我们了解到了Hook的好,所以就需要去革新旧的class组件。
官方举荐不需要专门为了hook去革新class组件,而且保证将继续更新class相关功用。
现实上我们也没有必要专门去革新旧项目中的class组件,由于工作量并不小。
可是我们完全可以在新的项目大要新的组件中去利用它。
总结

Hook是对函数式组件的一次增强,使得函数式组件可以做到class组件的state和生命周期。
Hook的语法加倍简便易懂,消除了class的生命周期方式致使的反复逻辑代码,治理了高阶组件难以大白和利用困难的题目。
但是Hook并没有让函数式组件能做到class组件做不到的事变,它只是让很多事变变得加倍简单而已。
class组件并不会消失,但hook化的函数式组件将是趋向。

免责声明:假如加害了您的权益,请联系站长,我们会实时删除侵权内容,感谢合作!
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

Archiver|手机版|小黑屋|理想论坛_专业20年的财经股票炒股论坛交流社区 - 股票论坛

GMT+8, 2020-7-3 05:08 , Processed in 0.165390 second(s), 28 queries .

Powered by Discuz! X3.2

© 2001-2013 Comsenz Inc.

快速回复 返回顶部 返回列表