React真的那么好用吗?

您好,我是沧沧凉凉,是一名前端开发者,目前在掘金知乎以及个人博客上同步发表一些学习前端时遇到的趣事和知识,欢迎关注。


这半年来,我一直在用React开发一个百万级的前端项目,由于最开始公司并没有这种对大型项目的人员储备,该项目预计的是半年内完成,也就是说到2021年年底就应该完成并且交付,但就目前来说并没有成功交付,还在继续开发中,

该项目的Web端几乎由我一个人完成,目前路由差不多300个左右,项目光src中的文件就已经过千,有些模块对应的页面文件夹都是密密麻麻的一片,但即便是这样,在开发这个项目的过程中,我几乎没有加过班,大部分都是6点出头就下班走人,最多的时候是对接3个后端的接口,最忙的时候一天对了接近50个接口。(至于我为什么3个多月都没有更文,其实是因为减肥,我从170斤成功减到了138斤)。

因为我之前的技术栈是Vue,自从我开始做这个项目的时候,我才正式用React开发项目,虽然之前我多多少少会一点React,包括我的个人主页,也是2021年年初的时候使用React进行搭建的。

但是在这个项目之前,我还没有用过React进行这种外包项目的开发,所以一开始我对我自己的信心是不足的,因为这个项目的体量毕竟很大,我是一个不喜欢加班的人,我怕选择了我不熟悉的技术栈会导致天天加班,然而从结果上来讲,React的开发效率实在是高,我觉得如果是使用的Vue技术栈,我是不可能一个人将这Web项目做到现在而几乎不加班。

就我个人认为,React的Hooks实在是太优秀了,对于这种大型的后台管理项目来说,有非常多的逻辑都可以通过Hooks进行复用,而且React的JSX语法也非常的优秀,它可以让你在JSX中直接使用其它地方声明的函数,变量。

最后由蚂蚁研发的ahooks以及Antd对React的加持,让React搭建后台类型的项目变得非常的容易以及非常的快捷,就我个人感觉来讲,使用这一套技术起码比使用Vue来进行搭建的速度快1~2倍,虽然Vue3已经有了Composition API,但相关的技术支持还不够成熟。

接下来就该进入重点,说一说React到底好用在哪儿。

事先声明:本篇文章并不是为了踩一捧一,只不过往往有对比才有伤害,国内目前用的最多的两个框架就是React和Vue,而且我使用这两个技术都有一段时间,所以对比起来也比较方便一点。

1. JSX

JSX非常的优秀,可以看下我的这篇文章,专门讲解了JSX相关的东西:迷人的JSX,你可以进行各种骚操作

2. Hooks

Hooks绝对是前端技术发展中的一个里程碑,它的出现解决了之前React项目两大痛点。

2.1 this问题

this指向问题在面试题中一直是一道常考的题,但在我写代码的过程中,Vue中的this问题已经由Vue进行了简化,虽然偶尔还是会遇到指向问题造成编写的代码得到意料之外的结果,比如说下面的这种情况:

由于我正式用React写项目就是使用的Hooks+函数组件,所以我不太清楚React上的this有哪些问题,所以这里以Vue进行举例。

<script>
export default {
  name: "App",
  data() {
    return {
      // 声明data的值
      data: "测试",
    };
  },
  methods: {
    showData() {
      function test() {
        // TypeError: Cannot read properties of undefined (reading 'data')
        // 预期是想调用上文中声明的data打印出 测试
        console.log(this.data);
      }

      // 这里调用后会报错
      test();
    },
  },
};
</script>

在没有箭头函数之前,需要这样写才能得到正确的输出:

<script>
export default {
  name: "App",
  data() {
    return {
      // 声明data的值
      data: "测试",
    };
  },
  methods: {
    showData() {
      function test() {
        // 这里会正确的打印 测试
        console.log(this.data);
      }

      // 通过call绑定this
      test.call(this);
    },
  },
};
</script>

在ES6发布了箭头函数后,可以这么写:

<script>
export default {
  name: "App",
  data() {
    return {
      // 声明data的值
      data: "测试",
    };
  },
  methods: {
    showData() {
      const test = () => {
        // 这里会正确的打印 测试
        console.log(this.data);
      };

      // 调用箭头函数
      test(this);
    },
  },
};
</script>

箭头函数里面的this会逐层往上查找,如果找到最外层都找不到该值,会返回undefined。我个人推荐,为了避免this带来的问题,在Vue2中或者React的class组件中,任何使用到this关键字的函数都使用箭头函数进行声明。

在React的class组件中,大量的难以理解的this指向问题给编写代码造成了非常多的麻烦,虽然后面由于箭头函数()=>的出现使得情况好一点,如果你看过React老教程,那么大部分教程都是使用的class组件,其中会使用到.bind.call.apply这些方法,而且由于JS特性的问题,this.xxx可能会被隐式声明,但是编辑器不会有任何提示。

我这里以Vue来举例这种情况,因为我曾经在别人写的代码中经常见到这种隐式声明,大大的增加了项目维护的难度。

image-20220110093148513

关于this带来的问题可以看一下我之前的这篇文章:老生常谈的this

而Hooks的出现直接抛弃了难以理解的this,减少了代码中大量的隐式BUG。

2.2 代码难复用

在Hooks之前,使用class组件编写的业务代码,是很难进行复用的,由于我对class组件并不是很熟悉,这里就说一下Vue中,因为Vue中其实也相当于是用的class组件,在Vue中可能两个业务页面都需要同样的属性和方法,那么只有使用mixin

但这个mixin虽然解决了业务代码复用的问题,但是也带来了新的问题,那就是维护起来非常麻烦,尤其是当一个组件中使用了几个mixin的时候,你在组件中调用某个方法或者变量,你很难找到这个方法、变量到底声明在哪儿的,尤其是当组件中业务代码又很多的情况。

我在项目中封装了大量的Hooks,比如说在中后台应用,非常多的下拉框的数据是需要从后端进行请求的,所以我从一开始就将这一个一个的下拉框请求封装成了Hooks。

虽然Hooks相对于传统的class组件来说拥有不完整的声明周期,但是在我个人编写本项目的过程中,完全没有任何的影响,可以解决目前我遇到的所有需求。

注:React官方推荐所有自定义Hooks都是以use开头。

后面的经历告诉我这样做是一个非常正确的选择,因为后端在测试的时候可能会更换接口,而如果后端调整了获取数据的接口,那么你只要调整这个Hooks,而不需要每个页面单独进行调整

3. TypeScript

React+TypeScript实在是太香了!在React中,TypeScript可以发挥出最大的功效,而Vue中的TypeScript就不行,我们直接来看下面的两个例子,就知道React+TypeScript和Vue+TypeScript到底哪儿不同。

<template>
  <div>这里是测试:{{ data }}<button @click="changeData">点我</button></div>
</template>

<script lang="ts">
export default {
  name: "App",
  data() {
    return {
      // 在对象中,TypeScript无法直接给予类型约束
      data: {
        name: "张三",
        age: 18,
        sex: "男",
      },
    };
  },
  methods: {
    changeData() {
      // 这里有些编辑器会显示any类型
      this.data = {};
    },
  },
};
</script>

而在React中:

// 声明接口
interface DataProps {
  name: string;
  age: number;
  sex: string;
}

// 这里可以直接用接口约束对象类型
const data: DataProps = { name: "张三", age: 18, sex: "男" };

export default function App() {
  return <div>这里是测试:{JSON.stringify(data)}</div>;
}

当然,我在这里也要帮Vue说句话,在Vue3中,对TypeScript的支持比起Vue2中好太多了,而且Vue2中也推出了装饰器来增强Vue对TypeScript的支持,可以看一下我的这篇总结文章使用装饰器和class关键字编写Vue2.x组件,但是就我个人觉得,还是无法发挥TypeScript的最大功效。

既然说到了TypeScript的优点,那我就来说说TypeScript的缺点,TypeScript的缺点非常的明显:上手难度高、不熟悉的情况下写起来麻烦!

对于前端开发者来说,大部分都没有学过静态语言,比如非常具有代表的Java,就因为TypeScript需要对类型进行声明,如果你没有引用TypeScript对应的Eslint,那么在大部分情况下,是不会强制你对参数以及变量进行类型声明的,这样你用着用着就发现你把TypeScript用成了JavaScript,失去了TypeScript大量的类型校验提示。

还有就是后端改接口类型,因为我这个项目对所有的请求接口都进行了请求参数和响应参数的声明,由于这个公司没有前端后端产品坐在一起先开会,然后再写项目的习惯,所以也没有确定原型图上的字段这一环节。

后端在大部分情况下,都会为了先实现功能草草出一个接口,当你进行了接口类型声明后,过一段时间后端往该接口上面加东西,你可能又要进行声明一次,然后后端每次一改接口你就需要重新进行声明,所以到了后期,我已经厌倦了,只要界面上面没有报错,我都不会重新去声明接口类型。

由于后端有些接口的字段非常多,如果在JavaScript上面接口声明可能也就100来行代码,但是在TypeScript上可能直接几千行的代码,当然在TypeScript上你也可以选择不声明接口类型,但这样的话你还不如就使用JavaScript,使用TypeScript就没有太大的意义,并且使用TypeScript,它可以帮你解决90%的因为undefined导致的页面报错!!!

我们直接来看下面的两段代码:

JavaScript有提示但不报错:

image-20220104175442892

TypeScript有报错:

image-20220104175314588

所以就我个人体验来讲,TypeScript是做大型项目的神器,但他同时会给你带来一点点效率上的降低,但是当你熟悉TypeScript后,书写起来的速度也不会比JavaScript速度低太多,因为代码编辑器对TypeScript的支持已经非常的完善了。

至于在项目中如何快速声明接口的请求参数和响应参数,其实是有非常多的工具可以直接将JSON转换为TypeScript的接口类型声明,我个人目前最常用的就是这个工具transform当然它仅仅只能转换接口类型,不能添加注释,所以我还专门写了一个小工具,可以将注释也自动添加上去。

4. 第三方生态

React的第三方生态实在是太全了,只要你想要的你都可以在社区找到解决方案,在这里我就说一个强烈建议学习的第三方库:styled-components,它能让你更快更方便的写出通用的组件。

强烈推荐下面的两个蚂蚁生态:

4.1 ahooks

蚂蚁封装了大量的实用的Hooks,尤其是网络请求这一块,一旦你用过你就会离不开它,反正现在我是已经无法离开useRequest这个Hooks了,aHooks可以看一下更多的React-Hooks:ahooks到底有多好用

4.2 ProComponents

蚂蚁在Antd的基础上再次封装了一套高级UI组件,ProComponents,用它来创建中后台项目实在是太过于方便,可以说很多页面交互,数据传递变得异常的简单,尤其是ProForm和ProTable这两个高级组件。

这一套高级组件封装了大量的东西,比如列表中的网络请求,表单中的网络请求,表单中的联动等等,唯一不足的就是每次包升级后可能会出现影响使用的BUG。

5. 化学反应

当你将ProComponents、ahooks、TypeScript、React…这些东西组合在一起,你就会发现用他们来开发中后台应用实在是太方便了,效率极高,即使是一些比较复杂的交互方式也能够轻易解决。

在项目中我还遇到了那种4个弹窗中的值互相传递,组合后统一传递给后端的情况,这些复杂的情况,如果你没有使用React,处理起来是一件非常麻烦的事情。

6. 最后

很多人其实是不太愿意尝试新技术的,因为使用其它技术可能会缺乏安全感,对项目是否能按时完工,而且别人接手可能也会带来一定的难度。

之前这个项目启动的时候我想要招个人来帮忙,面试快2个月一直没有招进来人,后面帮其它项目招Vue技术栈的人的时候,1周内就招到了合适的人选。

如果你是在一个小公司,并且项目可能涉及到迭代这种情况,最好不要用TypeScript,当时我面试的时候几乎没有人用TypeScript写过项目,而且就算让一个用过TypeScript,但是没有写过项目的人来接手,那么他会将TypeScript使用成JavaScript,到处都是any声明。