react+typescript+antd随笔(一)

最近在学习typescript,所以试着用typescript来写react项目,记录一下过程中遇到的一些问题及解决方法。

一、项目搭建

这里使用create-react-app脚手架搭建基于typescript的react项目,根据文档执行以下命令:

npx create-react-app my-app --typescript

创建好了之后会是如下的结构:

注:ts-demo对应my-app

现在执行

cd my-app && yarn start

可以看到项目正常运行了。
如果遇到启动报错问题,一般删除node_modules然后重新yarn install即可。

二、常见问题

项目搭建好之后我们就要开始着手项目开发,下面写一些开发中常见的问题。

1、路径别名设置

在开发中我们经常需要在当前文件内引入别的组件或者一些方法,如果都使用绝对或者相对路径来引用会变得很麻烦,所以一般都会在webpack的配置里面添加路径别名来解决这个问题:

resolve:{
  //一些其他的配置
  alias:{
    '@': paths.appSrc //这里的paths.appSrc就是src路径,详细请自己参阅config/paths.js
  }
 //一些其他的配置
}

如果是js版本,这样的话已经ok了,我们也可以正常的使用如下方式引入

 import { someComponent } from '@/components/someComponent';

但是在ts版本,这里会报错提示找不到模块,解决办法为:需要在tsconfig.json里加上如下配置:

"compilerOptions":{
  //这里是一些已经存在的其他配置
  //如下是需要添加的配置
  "baseUrl": "src",
    "paths": {
      "@/*": [
        "./*"
      ]
   }
}
2、css模块化

脚手架搭建好的项目已经配置了css模块化,预编译器采用的sass,所以你可以直接使用:

//app.tsx
import React from 'react';
import logo from './logo.svg';
import './App.css';
import styles from './app.module.scss';
import MceLayout from './routes/layout/layout';
import { Button } from 'antd';

const App: React.FC = () => {
  return (
    
); } export default App;
//app.module.scss
.app {
  color: #fff
}

但是你需要遵循后缀以.module.scss || .module.sass为后缀,正如webpack里配置好的规则:

//webpack.config.js
40 // style files regexes
41 const cssRegex = /\.css$/;
42 const cssModuleRegex = /\.module\.css$/;
43 const sassRegex = /\.(scss|sass)$/;
44 const sassModuleRegex = /\.module\.(scss|sass)$/;

423 // Opt-in support for SASS (using .scss or .sass extensions).
424 // By default we support SASS Modules with the
425 // extensions .module.scss or .module.sass
426{
427  test: sassRegex,
428  exclude: sassModuleRegex,
429  use: getStyleLoaders(
430    {
431      importLoaders: 2,
432      sourceMap: isEnvProduction && shouldUseSourceMap,
433    },
434    'sass-loader'
435  ),
436  // Don't consider CSS imports dead code even if the
437  // containing package claims to have no side effects.
438  // Remove this when webpack adds a warning or an error for this.
439  // See https://github.com/webpack/webpack/issues/6571
440  sideEffects: true,
441},
3、antd组件样式问题

如果项目用了antd,为了让组件的样式和组件一样模块化加载(不做配置的话需要全局引入antd的样式文件,这样有些没用到的组件的样式也加载了,影响性能),需要在package.json里进行如下配置:

"babel": {
    //一些已经存在的配置
    //添加如下配置
    "plugins": [
      [
        "import",
        {
          "libraryName": "antd",
          "style": "css"
        }
      ]
    ]
 }

4、react组件写法问题

在js版本(es6)的有状态组件里,写法大致如下:

//子组件
import React from 'react';
export default class Child extends React.Component{
  constructor(props){
    super(props);
    this.state = {
      count: 0
    }
  }
  render(){
    return(
      
click to add
) } }
//父组件
import React from 'react';
import Child from './child';
export default class Parent extends React.Component{
  constructor(props){
    super(props);
    this.state = {
      count: 0
    }
  }
  add = ()=>{
    this.setState({
      count: this.state.count + 1
    })
  }
  render(){
    return(
      
    )
  }
}

这样在子组件内调用父组件传递的值是可以的。但是,在typescript版本,需要在子组件内定义接口来声明props和state的类型,否则this.props.say()会报错提示say不存在:

类型“Readonly<{}> & Readonly<{ children?: ReactNode; }>”上不存在属性“add”。ts(2339)

如下解决,修改child.tsx(typescript版的react组件后缀为.tsx):

import React from 'react';
//定义props和state的类型接口
interface IProps {
  add: () => void; // () => void表示函数类型
}
interface IState {
  msg: string;
}
//把props和state的类型接口传入组件
export default class Child extends React.Component{
  constructor(props: IProps){
    super(props);
    this.state = {
      msg: 'hello world'
    }
  }
  render(){
    return(
      
click to add
) } }
注意:你可能会发现就算不传入state的类型,也可以正常访问this.state.xx,但是这样typescript就无法对state进行类型检查。导致也许你访问了一个state里不存在的属性也不会报错,就失去了使用typescript的意义。

5、http代理

业务场景:我们本地开发的时候调用某个接口,会存在跨域问题,此时我们需要采用代理来规避跨域。
如果只代理一个api地址,则只需要在package.json内添加如下内容:

"proxy": "http://api02.aliyun.venuscn.com" // 这里是以阿里云的免费api地址为例,换成你自己需要的地址即可

如果需要代理多个api地址,需要安装http-proxy-middleware:

yarn add @types/http-proxy-middleware
注意:在typescript环境下,安装所有的依赖包都需要以@types/为前缀,否则无法引入。

然后在src目录下新建setupProxy.js文件,并按照如下格式填写:

//setupProxy.js
//注:下面的例子都是以阿里云的免费api,实际项目中改为自己的地址即可
const proxy = require('http-proxy-middleware');
module.exports = function(app) {
  app.use(proxy(
    '/province',
    {
        target: 'http://api02.aliyun.venuscn.com',
        changeOrigin: true,
        secure: false,
        pathRewrite: {
            '^/province': '/',
        },
    },
  ));
  app.use(proxy(
    '/poetry',
    {
        target: 'http://jisutssbs.market.alicloudapi.com',
        changeOrigin: true,
        secure: false,
        pathRewrite: {
            '^/poetry': '/',
        },
    },
  ));
};

你的http请求文件中:


axios.get('/province/area/all?level=0');//此请求最终为:http://api02.aliyun.venuscn.com/area/all?level=0

axios.get('/poetry/tangshi/search?keyword=无');//此请求最终为:http://jisutssbs.market.alicloudapi.com/tangshi/search?keyword=无

注意:虽然本文是基于typescript,但是这个配置文件目前看来只能以.js为后缀(待验证),如果你执行了npm run eject后,会发现在config目录下的paths.js里配置的是setupProxy.js:
 //...
module.exports = {
  dotenv: resolveApp('.env'),
  appPath: resolveApp('.'),
  appBuild: resolveApp('build'),
  appPublic: resolveApp('public'),
  appHtml: resolveApp('public/index.html'),
  appIndexJs: resolveModule(resolveApp, 'src/index'),
  appPackageJson: resolveApp('package.json'),
  appSrc: resolveApp('src'),
  appTsConfig: resolveApp('tsconfig.json'),
  appJsConfig: resolveApp('jsconfig.json'),
  yarnLockFile: resolveApp('yarn.lock'),
  testsSetup: resolveModule(resolveApp, 'src/setupTests'),
  proxySetup: resolveApp('src/setupProxy.js'), //这里是引用的setupProxy.js文件
  appNodeModules: resolveApp('node_modules'),
  publicUrl: getPublicUrl(resolveApp('package.json')),
  servedPath: getServedPath(resolveApp('package.json')),
};

更多内容请参阅官方传送门

6、代码split,按需加载

这里我们使用react-loadable来进行代码分割,用法如下:

//router.ts
import React from 'react';
import { Route } from 'react-router-dom';
import Loadable from 'react-loadable';
import loading from './loading';

const Home = Loadable({
  loader: () => import('@/routes/home/view'),
  loading,
});
const routes = [
     }
    />,
];

export default routes;

这里在安装的时候遇到一个问题,首先执行:

yarn add @types/react-loadable

会发现我们的引入的地方没有提示找不到该模块了,但是运行却报错:


我们查看一下node_modules,发现实际上node_modules里面并没有安装该模块,仅仅是在@types里面添加了该模块的声明,所以还需要安装一下该模块:

yarn add react-loadable

重新启动即可。

源码github地址

该demo持续更新,所以github上面的代码和文章内的可能会有一些出入,最终以github上的为准,未完待续...

你可能感兴趣的:(react+typescript+antd随笔(一))