React 学习笔记

程序员成长之旅 · 程序员成长之旅/React学习 · 3190 字

[TOC]

React 学习笔记

创建React项目

JS版本


$ npx create-react-app my-app

可以按照提示自动执行npm install

TS版本


# 记录一个坑, 使用yarn创建的项目报错, 不要使用

$ npx create-react-app my-app --template typescript

配置React项目

如果你需要使用到下面所述的技术, 请参照, 否则可以直接开始使用项目, 无需配置

配置less(已不使用该种方式进行配置, 该种方式缺点甚多)

适用于JS项目, TS项目

默认情况下React项目已经配置好Scss, 但是没有配置less, 所以我们必须要手动配置

安装必要包


$ yarn add less less-loader

配置webpack

使用create-react-app脚手架创建的项目默认情况下会隐藏webpack配置文件, 所以第一步就是暴露配置文件

暴露配置文件
第一步, 如果存在git未提交的文件先要提交

$ git add .

$ git commit -m "保存所有更改, 以准备使用yarn eject"
第二部, 暴露所有配置文件(会暴露包括webpack在内的所有配置文件, 该操作不可逆)

$ yarn eject

根据提示输入y即可开始执行

配置相关文件

打开/config/webpack.config.js并执行以下修改(建议使用搜索功能找到响应位置)

配置less-loader

第一步, 添加用于匹配less文件的整个表达式


// 被该行注释包裹的内容没有修改↓

// style files regexes

const cssRegex = /\.css$/;

const cssModuleRegex = /\.module\.css$/;

const sassRegex = /\.(scss|sass)$/;

const sassModuleRegex = /\.module\.(scss|sass)$/;

// 被该行注释包裹的内容没有修改↑

// 新加入以下内容

const lessRegex = /\.less$/;

const lessModuleRegex = /\.module\.less$/;

第二部, 添加规则, 以应用上表达式


// 被该行注释包裹的内容没有修改↓

// Adds support for CSS Modules, but using SASS

// using the extension .module.scss or .module.sass

{

test: sassModuleRegex,

use: getStyleLoaders({

importLoaders: 3,

sourceMap: isEnvProduction ?

shouldUseSourceMap :

isEnvDevelopment,

modules: {

mode: 'local',

getLocalIdent: getCSSModuleLocalIdent,

},

},

'sass-loader'

),

},

// 被该行注释包裹的内容没有修改↑

// 新加入以下内容

{

test: lessRegex,

exclude: lessModuleRegex,

use: getStyleLoaders({

importLoaders: 1,

modules: true,

sourceMap: isEnvProduction && shouldUseSourceMap

},

"less-loader"

),

sideEffects: true

},

{

test: lessModuleRegex,

use: getStyleLoaders({

importLoaders: 1,

sourceMap: isEnvProduction && shouldUseSourceMap,

modules: true,

getLocalIdent: getCSSModuleLocalIdent

},

"less-loader"

)

},

至此配置完成

(可选)测试是否配置成功

测试文件


// /scr/Home/index.js

import style from './style.less';

function Home(){

console.log(style);

return(

<div className={style.root}>

<h1>Home page</h1>

</div>

)

}

export default Home;

// /scr/Home/style.less

.root{

h1{

color: red;

}

}

需要注意的是使用less和使用传统的css使用方式略有区别


// CSS

import './style.css'

...省略

<div className="root">

<h1>Home page</h1>

</div>

// less

import style from `./style.less`

...省略

<div className={style.root}>

<h1>Home page</h1>

</div>

(可选)配置使用'@'访问scr目录(已不使用该种方式进行配置, 该种方式缺点甚多)

适用于JS项目, TS项目

暴露配置文件

必须先暴露配置文件, 如果还没有这么做, 请参考上面文章中的配置lsss.配置webpack.暴露配置文件

配置webpack

打开/config/webpack.config.js并执行以下修改(建议使用搜索功能找到响应位置)


// 被该行注释包裹的内容没有修改↓

alias: {

// Support React Native Web

// https://www.smashingmagazine.com/2016/08/a-glimpse-into-the-future-with-react-native-for-web/

'react-native': 'react-native-web',

// Allows for better profiling with ReactDevTools

...(isEnvProductionProfile && {

'react-dom$': 'react-dom/profiling',

'scheduler/tracing': 'scheduler/tracing-profiling',

}),

...(modules.webpackAliases || {}),

// 被该行注释包裹的内容没有修改↑

// 添加以下内容

'@': path.resolve('src'),

// 添加以上内容

},

配置项目代码检查和风格统一(React + TS + Prettier + ESlint + Tailwind + Stylelint)

安装并配置Pretter(此步骤无需TS项目环境也可单独使用)

前置条件:

适用于JS项目, TS项目

安装
  1. 安装prettier到项目

$ npm install prettier -D
  1. 安装Visual Code中的插件Prettier - Code formatter

image-20220308160247504

配置
  1. 在项目根目录创建.prettierignore并填入如下内容

# /.prettierignore

# Ignore artifacts:

node_modules

dist

.vscode

.prettierignore
  1. 在项目根目录创建.prettierrc.js并填入如下内容

// .prettierrc.js

module.exports = {

printWidth: 140,// 换行长度, 超过这个长度要求强制换行

tabWidth: 2,// tab缩进长度

semi: true,// 强制分号结尾

singleQuote: true,// 强制使用单引号

trailingComma: 'none',// 强制使用拖尾逗号

bracketSpacing: true,// 强制在对象字面量的属性中键和值之间使用空格

bracketSameLine: false,// 将多行 HTML(HTML、JSX、Vue、Angular)元素放在最后一行的末尾,而不是单独放在下一行(不适用于自闭合元素)。

arrowParens: 'always',// 强制箭头函数参数使用圆括号

insertPragma: false,// 在文件顶部插入一个特殊的标记,标记指定文件已使用Prettier格式化。

requirePragma: false,// 强制在文件开头插入 @format 注释

useTabs: false// 使用tab缩进

};
  1. 在项目根目录文件夹.vscode(如果已存在则无需创建), 并在该文件夹下创建settings.json(如果已存在则无需创建)

// .vscode/setting.json

{

// (其他配置无需修改)

// prettier规则使用当前目录的.prettierrc.js

"prettier.configPath": ".prettierrc.js",

// 保存的时候自动格式化

"editor.formatOnSave": true,

}
测试

此时在任意js文件以及其他支持的文件输入代码并且保存即可成功格式化代码

安装Eslint并配置ESlint + Pretter

前置条件: 已经成功配置Prettier

适用于TS项目

安装
  1. 安装eslint包以及eslint用得到的相关插件

# 使用npm安装

npm i eslint -D

# 用于eslint配置文件中的parser配置:插件@typescript-eslint/parser让ESLint 对 TypeScript 的进行解析。

npm i @typescript-eslint/parser -D

# 用于eslint配置文件中的extends配置:为了防止eslint和prettier的规则发生冲突,我们需要集成两者则设置为['plugin:prettier/recommended']。

npm i eslint-config-prettier eslint-plugin-prettier -D

# 用于eslint配置文件中的plugins配置:

#     @typescript-eslint:包含了各类定义好的检测Typescript代码的规范。

#     react-hooks:为了检测和规范React hooks的代码规范检查的插件。

#     eslint-plugin-react:为了检测和规范React代码的书写的插件。

npm i eslint-plugin-react eslint-plugin-react-hooks @typescript-eslint/eslint-plugin -D

# 使用yarn安装

yarn add @typescript-eslint/parser eslint-config-prettier eslint-plugin-prettier eslint-plugin-react eslint-plugin-react-hooks @typescript-eslint/eslint-plugin -D
  1. 安装Visual Code中的插件ESLint

image-20220308162214026

配置

.eslintrc.js用于对ESlint做配置, .eslintignore用于配置ESlint对哪些文件不做格式化

  1. 在项目根目录创建.eslintrc.js并填入如下内容

module.exports = {

parser: '@typescript-eslint/parser', // 定义ESLint的解析器

extends: ['plugin:prettier/recommended'], //定义文件继承的子规范

plugins: ['@typescript-eslint', 'react-hooks', 'eslint-plugin-react'], //定义了该eslint文件所依赖的插件

env: {

//指定代码的运行环境

browser: true,

node: true

},

settings: {

//自动发现React的版本,从而进行规范react代码

react: {

pragma: 'React',

version: 'detect'

}

},

parserOptions: {

//指定ESLint可以解析JSX语法

ecmaVersion: 2019,

sourceType: 'module',

ecmaFeatures: {

jsx: true

}

},

rules: {

// 自定义的一些规则

'prettier/prettier': 'error',

'linebreak-style': ['error', 'unix'],

'react-hooks/rules-of-hooks': 'error',

'react-hooks/exhaustive-deps': 'warn',

'react/jsx-uses-react': 'error',

'react/jsx-uses-vars': 'error',

'react/react-in-jsx-scope': 'error',

'valid-typeof': [

'warn',

{

requireStringLiterals: false

}

]

}

};
  1. 在项目根目录创建.eslintignore并填入如下内容

# Ignore artifacts:

node_modules

dist

.vscode

.prettierignore

scripts

config

public

*.md
  1. .vscode/settings.json下做如下配置

{

// prettier规则使用当前目录的.prettierrc.js

"prettier.configPath": ".prettierrc.js",

"eslint.options": {

"extensions": [".js", ".ts", ".tsx", "jsx", "html"]

},

// 保存的时候自动格式化

"editor.codeActionsOnSave": {

// 保存时使用eslint进行格式化

"source.fixAll.eslint": true

},

// 应用eslint后对样式文件的格式化失效了, 手动样式文件格式化配置如下

"[css]": {

"editor.defaultFormatter": "esbenp.prettier-vscode",

"editor.formatOnSave": true

},

"[less]": {

"editor.defaultFormatter": "esbenp.prettier-vscode",

"editor.formatOnSave": true

},

}
测试

在支持的文件下如果代码有错误应该能看到ESlint的错误提示

安装并配置Taiwind

安装

$ yarn add -D tailwindcss postcss autoprefixer

$ npx tailwindcss init -p# 该命令会在根目录创建配置文件tailwind.config.js
配置
配置tailwind

在根目录找到tailwind.config.js并配置为如下


module.exports = {

content: [// 目的是清洗用不到的样式

"./src/**/*.{js,jsx,ts,tsx}",

],

theme: {

extend: {},

},

plugins: [],

}
引入tailwind

scr目录下找到index.css文件并在头部加入如下配置(如果没有该文件请找到创建React根脚本文件, 并找到其对应的样式文件, 如果没有请创建一个)


@tailwind base;

@tailwind components;

@tailwind utilities;

在React根脚本文件引入该样式


import React from 'react';

import ReactDOM from 'react-dom';

import App from './App';

import reportWebVitals from './reportWebVitals';

import './index.css';// 确保加入这一行

ReactDOM.render(

...

);
测试

请参照官方文档进行测试

将样式文件交给stylelint进行格式化

安装

yarn add -D stylelint stylelint-config-standard
配置

在项目根目录创建stylelint.config.js并填入如下内容


module.exports = {

extends: ['stylelint-config-standard'],

rules: {

'at-rule-no-unknown': [

true,

{

ignoreAtRules: ['tailwind', 'apply', 'variants', 'responsive', 'screen']

}

],

'declaration-block-trailing-semicolon': null,

'no-descending-specificity': null

}

};

禁止vscode使用默认规则对样式文件并检查.vscode/setiings.json


// .vscode/setting.json

{

"prettier.configPath": ".prettierrc.js",

"eslint.options": {

"extensions": [".js", ".ts", ".tsx", "jsx", "html"]

},

// 保存的时候自动格式化

"editor.codeActionsOnSave": {

"source.fixAll.eslint": true

},

// 如果存在类似这样的配置请将其删除

// "[css]": {

//     "editor.defaultFormatter": "esbenp.prettier-vscode",

//     "editor.formatOnSave": true

//   },

// "[less]": {

//     "editor.defaultFormatter": "esbenp.prettier-vscode",

//     "editor.formatOnSave": true

//   },

// 加入如下行

"css.validate": false,

"less.validate": false,

"scss.validate": false

}
测试

如果一切顺利, 你就可以在样式文件中看到错误提示, 以及保存后会自动修正错误的格式

启动React项目

启动项目


# 在项目目录输入如下命令即可启动项目, 默认端口3000

$ npm start

访问项目

访问localhost: 3000即可启动项目

使用React

使用Hooks

useState
基础使用

import { useState } from 'react';// Hook 是一个特殊的函数,它可以让你“钩入” React 的特性

function StateHook(param) {

// 为什么不适用createState这个名字来表示创建? "Create" 可能不是很准确,因为 state 只在组件首次渲染的时候被创建。

// 是否需要创建多个state变量来保持性能? 你不必使用多个 state 变量。State 变量可以很好地存储对象和数组,因此,你仍然可以将相关数据分为一组。然而,不像 class 中的 this.setState,更新 state 变量总是替换它而不是合并它。

const [count, setCount] = useState(0);// useState 方法的返回值是什么? 返回值为:当前 state 以及更新 state 的函数。

return (

<div>

{/* 可以直接使用Hook创建的变量 */}

<p>You clicked {count} times</p>

{/* 可以直接使用更新函数setCount来更新变量 */}

<button onClick={() => setCount(count + 1)}>

Click me

</button>

</div>

)

}

export default StateHook;
EffectHook

import { useState, useEffect } from 'react';

function EffectHook(){

const [count, setCount] = useState(0);

// Effect Hook 可以让你在函数组件中执行副作用操作

// 例如,在函数组件中,你可以使用 useEffect 来指定一个副作用函数,它在每次渲染组件时(包括首次渲染和后续的每次渲染)都会被调用。

useEffect(() => {

document.title = `You clicked ${count} times`;

});

return (

<div>

<p>You clicked {count} times</p>

<button onClick={() => setCount(count + 1)}>

Click me

</button>

</div>

)

}

export default EffectHook;

组件库

封装一个antd-mobileSwiper

支持的数据格式


items = [

{

img: 'https://s1.328888.xyz/2022/03/07/gUVyv.png',// 图片地址

href: 'https://baidu.com'// 指向链接

},

...

]

实现了以下特性:

  1. 支持链接形式的突破, 并且可以附带该图片的目标地址

  2. 支持传入useState创建的变量

  3. 如果目标数据需要从服务器获取, 无需做任何操作, 直接更新useState创建的变量即可

  4. 支持后续再向组件添加图片


// src/Home/MySwiper/index.js

import { Swiper } from 'antd-mobile';

import style from './style.less';

function MySwiper(props){

// console.log('in MySwiper props: ', props);

const { items } = props;

function getSwiperDatas(){

console.log(items);

if(items.length > 0){

return items.map((item, index) => {

return (

<Swiper.Item key={index}>

<div className={style.swiperItem} onClick={() => {onClickItem(index)}}>

<img src={item.img} alt={item.alt} />

</div>

</Swiper.Item>

)

})

}else{

return (

<Swiper.Item key={0}>

<div className={style.swiperItem}>

<img src="https://s1.328888.xyz/2022/03/07/geux2.png" />

</div>

</Swiper.Item>

)

}

}

function onClickItem(index){

console.log('in targetToImgHref index: ', index);

}

return(

<Swiper className={style.Swiper}>{getSwiperDatas()}</Swiper>

)

}

export default MySwiper;

// src/Home/MySwiper/style.less

.Swiper{

width: 100%;

height: 100%;

.SwiperItem{

width: 100%;

height: 100%;

}

}

// src/Home/index.js

import { useState } from 'react';

import style from './style.less';

import { Button } from 'antd-mobile'

import Swiper from './MySwiper/index.js';

function Home(){

console.log(style);

const [fakeSwiperDatas, setFakeSwiperDatas] = useState([]);

function insertFakeSwiperData(){

setFakeSwiperDatas(oldArray => [...oldArray, {

img: 'https://s1.328888.xyz/2022/03/07/gUVyv.png',

href: 'https://baidu.com'

}])

console.log(fakeSwiperDatas)

}

function initFakeSwiperData(){

setFakeSwiperDatas([

{

img: 'https://s1.328888.xyz/2022/03/07/gUVyv.png',

href: 'https://baidu.com'

},

{

img: 'https://s1.328888.xyz/2022/03/07/gUVyv.png',

href: 'https://baidu.com'

},

{

img: 'https://s1.328888.xyz/2022/03/07/gUVyv.png',

href: 'https://baidu.com'

},

{

img: 'https://s1.328888.xyz/2022/03/07/gUVyv.png',

href: 'https://baidu.com'

}

])

}

return(

<div className={style.root}>

<h1>Home page</h1>

<h2>Swiper</h2>

<Button color='primary' onClick={initFakeSwiperData}>接收到服务器传来的图片地址</Button>

<Swiper items={fakeSwiperDatas}></Swiper>

</div>

)

}

export default Home;

前两个代码块是Swiper的封装实现, 最后一个代码块是调用该封装