从 Vueer转到 Reacter的心路历程

2,587 阅读5分钟

1 从 Vue 技术栈转到 React 技术栈的历程

大家好,我是 Jone,有两年的前端开发经验,19 年在某鸟培训机构学习,学习了HTML CSS JS三件套的一点点皮毛,再加上Vue2的技术栈,就出来找工作了,毕业之后又刚好赶上疫情,通过视频面试的方式,艰难的找到了第一份工作,公司用的是Vue2+ElementUI开发,工作一年的时间,也慢慢掌握了公司的业务,做的也就是一些表单表格,没有任何提升的空间,想突破一下自己,就主动提出离职了。第二年经过同事的内推,进了一家使用Vue3+Vite+Antd技术栈的公司,当时Vue3刚出来不久,也算是第一个吃螃蟹的了哈哈哈,后来因为公司经营问题倒闭了,不得不又开始找工作,工资至今未发。今年来到大上海,重新开始找工作之路,目前这一家公司的技术栈是React Hooks+TypeScript+微前端qiankun+Umi+Dva+Antd刚开始对于一个从没接触过React技术栈的我来说十分陌生,也走过不少弯路,不过作为一个有着一年多的开发经验Vueer,还是有一点组件化 函数式编程的基础,这两个技术栈之间也有许多相似之处,后来经过一两个月的摸索,从一开始进公司的看不懂代码,终于到现在可以掌握正常的开发业务。

2 脚手架的路由差异

之前 Before

之前Vue用的脚手架是Vue Cli搭建的脚手架,路由也是用的Vue的生态Vue Router

之后 After

现在用的是Umi搭建的脚手架,中文发音乌米,和Vue技术栈不同的是Umi集成了react react-router 开箱即用。同时还内置了请求库Umi request、数据管理dva等。

3 数据及状态管理的差异

之前 Before

我们在Vue 技术栈时通常使用axios二次封装,并且在src目录下新建一个api的文件夹来对我们系统的每个模块的接口进行统一管理。

src
  |-- components
  |-- api  请求接口统一管理

在页面中导入 api 的接口,在methods里面定义一个方法,在mounted生命周期函数里调用。

import {getTableList} from '@/api/policySystem'

export default {
  data() {
    return {
      tableData: []
    }
  },
  mounted() {
      this.getTableList()
  },
  methods:{
    async getTableList(){
      const data = {
        'strMap.taskid':'203537773243756544',
      }

      const res = await getTableList(data)
      if (res.success) {
        this.tableData = res.data.zctx
      }
    }
  }
}

获取到接口数据后再对 data 进行赋值,data 里的数据改变,触发视图的更新渲染。

之后 After

现在数据请求用的是Umi-requestUmi-request 是基于 fetch 封装的开源 http 请求库,统一的 API 调用方式,同时简化使用方式,提供了请求层常用的功能

  • URL 参数自动序列化
  • POST 数据提交方式简化
  • Response 返回处理简化
  • 请求超时处理
  • 请求缓存支持
  • GBK 编码处理
  • 统一的错误处理方式
  • 请求取消支持
  • Node 环境 http 请求
  • 拦截器机制
  • 洋葱中间件机制
特性umi-Requestfetchaxios
query简化×
post简化××
请求超时×
请求缓存××
错误检查××
错误处理×
请求拦截器×
前缀××
后缀××
中间件××
取消请求×

我们通常在src 目录下会生成一个services文件夹,来对接口进行统一管理。

public                  // 公共文件 可以放一些第三方字体 样式库等
mock                    // mock文件
src
  |-- components        // 公共组件目录 当业务需要拆分组件的时候,可以在对应的业务文件夹下单独创建一个components文件夹
  |-- layouts           // 项目结构文件
  |-- locales           // 规划文件
  |-- models            // 公共model存放位置
    |-- public.js       // 公共model文件 可以多个
  |-- services          // 公共api存放

数据层的管理用到了dva, dva是基于ReduxRedux-Saga的数据流方案,一个轻量级的应用框架。

  • Page 负责与用户直接打交道:渲染页面、接受用户的操作输入,侧重于展示型交互性逻辑。
  • Model 负责处理业务逻辑,为 Page 做数据、状态的读写、变换、暂存等。
  • Service 负责与 HTTP 接口对接,进行纯粹的数据读写。

先创建Model

import { ServiceData } from '@/services'//  是引入service层定义的请求接口方法名
 

 export default{
     namespace:'tableModel',
     state:{
      tabaleData:[]
      },
     reducers:{
      //同步方法
        saveTable(state,{payload}) {
          return {...satate.tabaleData,...plyload}
        }
      },
     effects:{
       // 异步方法
        * fetchTable(payload,{call,put}) {
            const { data } = yield call(ServiceData, payload) // ServiceData是引入service层定义的请求接口方法的名字,payload是请求传递的参数,data是后台返回的接口
        yield put({
 
          type"saveTable",// 这就是reducer中fetchTable方法, put就是用来触发上面reducer的方法,payload里就是传过去的参数。 同时它也能触发effects中其他方法。
 
          payload: {
            payload: data, // 把后台返回的数据赋值给了payload
          },
      }
      }
 }
  • namespace 命名空间 唯一的名字
  • state 初始数据
  • reducers 同步的方法
  • effects 异步的方法

使用effects定义异步方法,使用call方法调用Service层定义接口的方法,然后在使用put调用同步方法触发reducers, 类似Vuexmutation方法,是数据唯一的提交方式,然后reducers把数据返回给state

Index页面

import React from 'react';
import { connect } from 'dva'

const Index = ({tabaleData}) => {
 return <List data={tabaleData} />;
}

const mapStateToProps = ({ tableModel }) => {
  return {
    tableData: tableModel.tabaleData,
  };
};

const mapDispatchToProps = dispatch => ({
  fetchTableList(payload) => {
    disdpatch({
      type'tableModel/fetchTable',
      payload,
    });
  },
});

export default connect(mapStateToProps, mapDispatchToProps)(Index);

使用connect 让页面和Model进行连接,通过mapDispatchToProps用来调用Model层的方法,通过disdpatch派发一个对象进行触发,再使用mapStateToPropsprops对应Modelnamespace,返回一个对象,里面是获取Model的数据,组件接收props获取到数据在组件里使用。

dva 这样设计页面里只用接收porps数据展示,model层专注逻辑处理,这样虽然写起来会相对麻烦一些,但是代码写起来更加清晰明,后期可维护性也更高了,爱了爱了。