记一次用vite搭建react的经历
初衷
本篇文章只为记录一次用 vite
搭建react
的经历与踩坑。
背景
公司要开发一个新的项目,需要和别的部门合作一起开发,但是我们(当时)目前的技术栈是用CRA
搭建的,主要是react
管dom,mobx
管数据,react-router
管路由等,而且大部分组件都还在class
组件。算是比较老了。
而对方那边的项目则是用vite
构建的,而且上了ts
。虽然自己当时已经有使用CRA
搭建react-ts
的经验了,但是还是在路上踩了不少坑,以为方便。
开始搭建
首先我们用vite
创建项目:
1 | yarn create vite my-react-ts-app --template react-ts |
然后我们进入目录,目录结构是长这样的:
1 | ➜ ~ cd my-react-ts-app |
然后安装依赖:
1 | ➜ my-react-ts-app yarn |
然后我们可以运行yarn dev
,这样一个ts-react
就起来了。
加入装饰器
其实一般的项目到这里也就结束了,感觉也没什么好说的。
但是你要上ts
肯定就要用上装饰器的。
而且我的大部分时间也是卡在了这里,下面我们就用一个例子来说明。
首先,准备一个class
组件
1 | // ./src/MyClassComp.tsx |
然后,我们来写一个高阶组件。
1 | // ./src/MyHOC.tsx |
上面我们写了一个简单的HOC
,用来增强组件,即每次成功渲染之后都打印一个1
。
基本的使用:
1 | // ./src/main.tsx |
渲染页面看到打印1
就是成功使用了,但是我们不想要这样,因为如果参数过多的话,代码就不是很好看了,再者,从逻辑上说,增强组件的功能在组件内部也有提现,比如像withRouter
这样的高阶组件。所以我们还是需要装饰器的写法更为优雅。
ok, 我们把./src/main.tsx
还原,在./src/MyClassComp.tsx
用装饰器试试.
1 | // ./src/MyClassComp.tsx |
然后我们运行会发现有一个报错
1 | [vite] Internal server error: ~/my-react-ts-app/src/App.tsx: Support for the experimental syntax 'decorators-legacy' isn't currently enabled (6:1): |
这里是说我们没有装饰器的插件decorators-legacy
,而且报错标注了是react-babel
的。我们去vite.config.ts
配置一下。
1 | // vite.config.ts |
可以看到这里与CRA
不同的点,cra
需要你自己安装babel
插件来转义,我们这里没有用任何的插件,因为vite
内置了,这也是对开发者友好的一个点。
配置完成之后,你可以看到页面完美运行,且高阶组件也生效了。
加入Mobx
因为公司这边是用mobx
管理状态的,这边我也花了一点时间在这上面,这里我也记下。
首先我们准备好mobx
。
安装必要的库。
1 | yarn add mobx mobx-react |
准备好一个测试的store:
1 | // ./src/mobx/testStore.ts |
用一个工具文件来存储常用函数:
1 | // ./src/util.ts |
准备好reduce
,这一步你可能不需要,因为我是从redux
先学的,习惯放一个reduce
1 | // ./src/mobx/reduce.ts |
把store
应用到react
上面
1 | // ./src/main.tsx |
以上这些准备工作,你觉得不做过多的解释,需要了解的可以去Mobx.js官网查看
OK,准备工作做完了,你打算在组件里面运用上mobx
的管理。
1 | // ./src/MyClassComp.tsx |
如果你这时候运行的话,页面渲染看起来是没有什么问题的,为什么是看起来没有问题,因为你点击一下add 1
按钮,你就会发现,控制台报错。我能料想到,差不多是这样的:
1 | action.ts:68 Uncaught TypeError: Cannot read properties of undefined (reading 'num') |
你通过了解报错信息发现是读取num
这个属性引发的,因为读取的对象是undefined
,结合我们点击add 1
按钮来看,你觉得应该是15
行这里出错了:
1 | 13 @action.bound |
这里的this
取不到值,那我们就换成箭头函数,让this
不用指向上下文,而是指向store
本身。
换完之后,你再点击的时候就没有报错了。终于正常了,到这里似乎一切还顺利,但是你很快就发现,无论你怎么点击,页面上渲染的值还是0
,没有变化。
不对啊,我们明明在组件上进入了观察者模式才对啊。
这里需要另外一个api
来修复这个了。我们在store
的constructor
里面加入一句话:
1 | // ./src/mobx/testStore.ts |
并且我们可以移除所有的@action.bound
。
我们在一次点击的时候你就可以看到页面上的num
是正常渲染了。
但是,这时候细心的你一定还是发现了控制台的警告:
1 | Since strict-mode is enabled, changing (observed) observable values without using an action is not allowed. Tried to modify: TestStore@1.num |
你发现这是点击async add
引发的问题。查阅官网之后你发现,需要要用这样一个api
:
1 | // ./src/mobx/testStore.ts |
之后的数据管理终于没有感叹号发生了,大功告成!
mobx的hooks版本
上述的一切都是简历在class component
上面的,但是与我们一起开发的还有其他的同事,怎么的也得把hooks
给支持了吧
得,你又写了一个function component
:
1 | // ./src/MyFunctionComp.tsx |
这里,你知道,运行起来肯定报错,因为testStore
都没有定义。怎么拿到自己的store
呢?
查阅官网之后你发现一个解决方案。
1 | // ./src/mobx/useStores.ts |
有了这个hooks
,我们就可以在组件里面这样定义store
了:
1 | const {testStore} = useStores(); |
运行之后,你发现点击按钮没有反应,页面渲染的num
始终是0
这时候,你仔细查看代码发现没有进入观察者模式。于是你加上observer
:
1 | // ./src/MyFunctionComp.tsx |
于此,对于hooks
也支持了。
共勉~