React学习(脚手架学习)

创建React+webpack+ts项目

npx create-react-app my-app --template typescript(tsx)

npx create-react-app my-app (jsx)

  •  创建成功后 cd ./my-app
  • 在终端使用 npm run eject /yarn enject暴露隐藏的webpack隐藏文件(此操作不可逆)
    该指令执行完毕后多出一个config文件

 webpack配置

配置项目路径别名

  • webpack配置地址
  • 找到配置项 module.exports 内含有一个名为 resolve 的属性,此属性下存在一个名为 alias 的对象子属性。这个 alias 对象用于配置一系列键值对,其中键作为模块引入时的简写别名,而对应的值则是实际的绝对路径,Webapck 编译过程中会根据这些别名规则来重定向模块导入请求。(src的路径不要配错,根据自己文件位置配置)
      "@":path.resolve(__dirname,'../src'),
      'pages':path.resolve(__dirname,"../src/pages"),

 解决别名提示问题

  • 打开tsconfig.json文件(同样的看好自己文件位置,不要配错!!!
       //配置名称:["地址"]
        "baseUrl": "./",
        "paths": {
        
          "@/*": ["src/*"],
          "pages/*": ["src/pages/*"],
          "images/*": ["src/images/*"],
        },

热更新配置 

  • 找到webpack文件进行配置

引入scss文件报错

  • 解决方法(报错原因是版本不一样,安装之后需要重启项目) 
npm/pnpm/yarn install node-sass@7.0.1
npm/pnpm/yarn install sass-loader@7.0.1

ts定义使用

typeinterface的区别

  • type(类型别名):你可以使用type关键字来创建新的类型别名或者联合类型、元组类型、枚举类型等复杂类型。TypeScript中的类型别名不会进行类型合并,如果有多个同名的type声明,只有最后一个会生效。
  • interface(接口声明)接口可以被多次声明并且自动合并,这意味着在不同位置定义的同名接口将会合并它们的所有属性和方法。

 联合类型

// 联合类型允许一个变量在同一时间拥有多种可能的类型
//通过管道符号 | 连接起来,当一个值的类型是联合类型时,它必须是该联合类型中列出的一种类型。
type id = number | string

function printId(id:id) {
  console.log("Your ID is: " + id);
}

 元组类型

// 元组类型用来表示一个已知固定长度和类型的数组,各元素的类型不必相同。
// 元组类型通过在方括号 [ ] 内列出各元素类型来定义。
type TupleTypeExample = [string, number, boolean];

let tuple: TupleTypeExample = ["Hello", 42, true]; // OK
tuple = ["World", 84]; // Error, 缺少一个元素
tuple = ["Hello", 42, true, null]; // Error, 多了一个元素

 枚举类型

// 枚举类型(Enum)用于定义一组命名的常量。
// 每个枚举成员都有一个值,可以是数字(默认自增,也可以手动指定)、字符串或其它枚举类型。
// 枚举提供了友好的、易于记忆的名称来代替难以理解的数值或字符串。
enum Color {
  Red,
  Green,
  Blue
}

let colorName: Color = Color.Red; // OK
colorName = 0; // OK,枚举成员的值默认从0开始,Red的值为0
console.log(Color[0]); // 输出 "Red",可以通过枚举值获取枚举名

// 自定义枚举值
enum ColorWithValue {
  Red = 1,
  Green = 2,
  Blue = 3
}

let colorWithValue: ColorWithValue = ColorWithValue.Red; // OK
colorWithValue = 1; // OK
enum StringColor {
  Red = "red",
  Green = "green",
  Blue = "blue"
}

let stringColor: StringColor = StringColor.Red; // OK
stringColor = "red"; // OK
   // 不使用枚举
   function processStatusCode(statusCode: number) {
     if (statusCode === 200) {
       // ...
     } else if (statusCode === 404) {
       // ...
     }
   }

   // 使用枚举
   enum HttpStatusCode {
     Ok = 200,
     NotFound = 404
   }

   function processStatusCode(statusCode: HttpStatusCode) {
     if (statusCode === HttpStatusCode.Ok) {
       // ...
     } else if (statusCode === HttpStatusCode.NotFound) {
       // ...
     }
   }

交叉类型 

//通过 & 符号将多个类型合并在一起,表示一个值必须同时满足这些类型的所有要求。

   interface Person {
     name: string;
   }

   interface Employee {
     id: number;
   }

   type EmployeePerson = Person & Employee;

 映射类型

// 映射类型(Mapped Types): 基于现有类型,通过映射操作符(如[P in K])生成新类型。
// 新类型通常是对原类型的键值对进行某种操作(如添加、删除属性、修改访问修饰符等)。

   interface Base {
     a: string;
     b: number;
   }

   type ReadonlyVersion = {
     readonly [P in keyof Base]: Base[P];
   };
创建只读版本的类型
// 创建只读版本的类型: 如果你想创建一个与现有类型具有相同属性,但所有属性都是只读的类型,
// 可以使用映射类型加上readonly关键字。
   interface Person {
     name: string;
     age: number;
   }

   type ReadonlyPerson = {
     readonly [P in keyof Person]: Person[P];
   };

   const person: Person = { name: 'Alice', age: 30 };
   const readOnlyPerson: ReadonlyPerson = person; // 可以赋值,但不能修改属性
   readOnlyPerson.name = 'Bob'; 
  // 错误:Cannot assign to 'name' because it is a read-only property.
 添加属性
// 添加属性到现有类型: 如果你想在现有类型的基础上添加一些额外的属性,可以使用映射类型结合&操作符。
   interface Person {
     name: string;
     age: number;
   }

   type PersonWithAddress = {
     [P in keyof Person]: Person[P];
   } & {
     address: string;
   };

   const personWithAddress: PersonWithAddress = {
     name: 'Alice',
     age: 30,
     address: '123 Main St.'
   };
删除属性
//删除属性: 使用Omit<T, K>内置实用类型可以创建一个省略某些属性的新类型。
   interface Person {
     name: string;
     age: number;
     address: string;
   }

   type PersonWithoutAddress = Omit<Person, 'address'>;

   const personWithoutAddress: PersonWithoutAddress = {
     name: 'Alice',
     age: 30
   };
 有条件添加属性
// 有条件地添加属性: 使用[P in K]?: T[P]语法可以创建一个新类型,其中某些属性是可选的。
   interface Person {
     name: string;
     age: number;
   }

   type PartialPerson = {
     [P in keyof Person]?: Person[P];
   };

   const partialPerson: PartialPerson = {
     name: 'Alice' // 只需提供部分属性
   };
 修改属性类型
// 修改属性类型: 使用映射类型可以将原有属性的类型转换为新类型。

   interface Person {
     name: string;
     age: number;
   }

   type PersonWithNullableAge = {
     [P in keyof Person]: P extends 'age' ? number | null : Person[P];
   };

   const personWithNullableAge: PersonWithNullableAge = {
     name: 'Alice',
     age: null // age现在可以是null
   };

泛型 

// 泛型(Generics): 提供了一种在定义函数、接口、类等时,保持类型参数化的能力,
// 允许在编译时传入具体类型来替代这些参数。

   function identity<T>(arg: T): T {
     return arg;
   }
函数泛型 
   function identity<T>(arg: T): T {
     return arg;
   }

   let output = identity<string>("Hello"); // output 类型为 string
   let numOutput = identity<number>(42); // numOutput 类型为 number
接口泛型
   interface Pair<K, V> {
     key: K;
     value: V;
   }

   let stringPair: Pair<string, number> = { key: "name", value: 30 };
   let booleanPair: Pair<boolean, string> = { key: true, value: "yes" };
 类泛型
   class Box<T> {
     private _value: T;

     constructor(value: T) {
       this._value = value;
     }

     get value(): T {
       return this._value;
     }
   }

   let stringBox = new Box<string>("Hello");
   let numberBox = new Box<number>(42);

 索引签名

// 索引签名(Index Signatures): 定义对象类型可以使用哪些类型的索引来访问其属性。

   interface Dictionary<T> {
     [key: string]: T;
   }

 类型断言

// 类型断言(Type Assertions): 在编译时强制告诉编译器某个值具有特定类型。
// 有两种形式:<Type>value或value as Type

   let someValue: any = "Hello";
   let strLength: number = (<string>someValue).length; // 类型断言为string

eslint配置

react项目中配置elint,启用保存自动化格式功能

安装eslint

// typescript eslint安装
 npm i eslint typescript

// 创建eslint文件
  npx eslint --init

以上的解释

  1. ESLint 的使用方式:你选择了 "problems",意味着 ESLint 将专注于找出代码中的问题和潜在的错误。
  2. 项目中使用的模块类型:你选择了 "none",表示你的项目不特别依赖于某种模块系统(如 ES6 模块或 CommonJS)。
  3. 使用的框架:你指明项目使用了 "react",这意味着 ESLint 配置需要支持 React 特定的规则和最佳实践。
  4. 是否使用 TypeScript:最初你选择了 "No",但似乎这里有一个更正,应该是选择了 "Yes",表明你的项目中实际上使用了 TypeScript。
  5. 配置文件格式:你选择了 "JavaScript",即你希望 ESLint 配置文件以 .js 格式存在。
  6. 代码运行环境:你选择了 "browser, node",这说明你的代码既要在浏览器环境中运行,也需要在 Node.js 环境下工作。

配置vscode的自动保存格式化 

这个可以根绝自己的配置进行配

{
  "eslint.run": "onType",
  "eslint.options": {
    "extensions": [".js", ".vue", ".jsx", ".tsx"]
  },
  "editor.codeActionsOnSave": {
    "source.fixAll.eslint": true
  },
 
  // 编辑器设置 - 保存时做格式化
  "editor.formatOnSave": true,
  // 编辑器设置 - 默认采用prettier-now做格式化
  // 如果使用的是prettier,这的设置应该是 esbenp.prettier-vscode
  "editor.defaultFormatter":"remimarsal.prettier-now",
 
  // 控制缩进
  "prettier.useTabs": false, // 缩进不使用tab,使用空格 
  "prettier.tabWidth": 2, // 缩进字节数
  
  // 函数声明时小括号前后要加空格
  // 如果你使用prettier这一项是不能做选择的,导致和eslint默认配置的冲突
  // 可以在百度中搜到很多的记录: https://www.baidu.com/s?wd=prettier%20%E5%87%BD%E6%95%B0%E7%A9%BA%E6%A0%BC
  "prettier.spaceBeforeFunctionParen": true,
 
  // react的jsx让>与结束标签同行
  "prettier.jsxBracketSameLine": true,
  "prettier.bracketSpacing": false, // 去掉数组内部前后的空格
  "prettier.semi": false, // 不要给语句加;
  "prettier.singleQuote": true, // 采用单引号
  "prettier.trailingComma": "none", // 不要尾随逗号,
  "prettier.printWidth": 80, // 每行超过80列就换行
 
  // 在.js中,写div按下tab就可以自动补全,而不需要写<div再补全
  "emmet.includeLanguages": {
    "javascript": "javascriptreact"
  }
}

  • 22
    点赞
  • 26
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值