Recat学习

  • Post author:
  • Post category:其他




1. 创建React项目

为了加速npm下载速度,先把npm设置为淘宝镜像地址。

npm config set registry http://registry.npm.taobao.org/
// 安装yarn
npm install -g yarn
// 安装cnpm
npm install -g cnpm -registry=https://registry.npm.taobao.org
//设置国内源
yarn config set registry https://registry.npm.taobao.org/

也可以使用cnpm,根据喜好自行选择。创建react项目,nodejs版本最好选择14以上。

通过官方的create-react-app,在自创建的目录执行:

npx create-react-app react-app

命令最后的react-app是项目的名称,可以自行更改。安装完成后,可以使用npm或者yarn启动项目。进入项目目录,并启动项目:

cd react-app
yarn start  (或者使用npm start)

如果没有安装yarn,可以前往yarn中文网站安装:https://yarn.bootcss.com/

启动后,可以通过以下地址访问项目:http://localhost:3000/

在这里插入图片描述

安装为最新的react版本,为18.2.0,create-react-app是基于 webpack 的打包层方案,包含 build、dev、lint 等,他在打包层把体验做到了极致,但是不包含路由,不是框架,也不支持配置,都需要自行解决。



2. 暴露配置文件



方法一

如果希望做一些自定义的系统配置,可采用下列方法。

执行以下命令,暴露配置文件:

npm run eject (yarn eject)

如果之前没有提及git的话,可能会报以下错误:

Remove untracked files, stash or commit any changes, and try again

需要先在项目根目录下执行:

git add .
git commit -m "初始化项目(备注)"

react-scripts 是 create-react-app 的一个核心包,一些脚本和工具的默认配置都集成在里面,而 yarn eject 命令执行后会将封装在 create-react-app 中的配置全部反编译到当前项目,这样用户就能完全取得 webpack 文件的控制权。所以,eject 命令存在的意义就是更改 webpack 配置。npm run eject 会复制所有依赖文件和相应的依赖(webpack、babel等)到你的项目。是个单项操作,一旦 eject ,就回不去了,如果想要回到正常的项目中去,只有重新 npm install create-react-app -g 了。



方法二

采用上述方法不可逆,生成的内容也比较多。推荐使用第三方工具,采用react-app-rewired插件方式,它的作用是用来帮助你重写react脚手架配置。react-app-rewired@2.x版本需要搭配customize-cra使用,customize-cra的作用是帮助你自定义react脚手架2.x版本配置。

  1. 安装
npm intall react-app-rewired customize-cra --save-dev (yarn add react-app-rewired customize-cra --dev)
  1. 修改package.json,原本的react-script 改为react-app-rewired
"scripts": {
    "start": "react-app-rewired start",
    "build": "react-app-rewired build",
    "test": "react-app-rewired test --env=jsdom",
    "eject": "react-scripts eject"
  },
  1. 在根目录下新建文件config-overrides.js文件
module.exports = function override(config, env) {
  // do stuff with the webpack config...
  return config
}
  1. 设置浏览器不启动,BROWSER=none&&之间不能有空格:
"scripts": {
    "start": "set BROWSER=none&&react-scripts start",
 }
  1. proxy

    开发环境下跨域问题,前端一般是给本地的devServer设置代理

安装http-proxy-middleware:

cnpm install http-proxy-middleware --save-dev
cnpm install axios --save

在src/目录下新建文件setupProxy.js(注意:文件名不能修改!!cra会按照src/setupProxy.js这个路径解析)

const { createProxyMiddleware } = require('http-proxy-middleware');

module.exports = function(app) {
  app.use(createProxyMiddleware('/api', {
    target: 'http://localhost:3001/',
    changeOrigin: true,
    // pathRewrite: {
    //   '^/api': ''
    // }
  }))
}
  1. 支持别名:
const {
  override,
  // ...
  addWebpackAlias
} = require('customize-cra')
const path = require('path')
function resolve (dir) {
  return path.join(__dirname, '.', dir)
}
module.exports = override(
  // ...
  // 路径别名
  addWebpackAlias({
    '@': resolve('src')
    '@components': resolve('src/components'),
    '@pages': resolve('src/pages')
  })
)
  1. 按需加载 babel-plugin-import
// babel-plugin-import 是一个用于按需加载组件代码和样式的 babel 插件
yarn add babel-plugin-import --dev
//引入
const { fixBabelImports } =require('react-app-rewired');
//使用
module.exports =function override(config, env){
    // 针对antd 实现按需打包:根据import来打包 (使用babel-plugin-import)
    fixBabelImports('import',{
        libraryName:'antd',
        libraryDirectory:'es',
        style:true,//自动打包相关的样式 默认为 style:'css'
    }),
  };
  1. 其他配置支持
module.exports = function override(config, env) {
  // do stuff with the webpack config...
  return config
}
const {
  override,
  fixBabelImports,
  addWebpackModuleRule,
  addPostcssPlugins
} = require('customize-cra');
const path = require('path');
const { name } = require('./package.json');
const paths = require('react-scripts/config/paths');
paths.appBuild = path.join(path.dirname(paths.appBuild), name);
 
module.exports = override(
  (config) => ({
    ...config,
    devtool: config.mode === 'development' ? 'cheap-module-source-map' : false,
  }),
  fixBabelImports('import', {
    libraryName: 'antd',
    style: 'css',
  }),
  addWebpackModuleRule({
    test: /\.(png|jpg|gif|jpeg|svg)$/i,
    use: [{
      loader: 'url-loader',
      options: {
        limit: 20 * 1024,
        esModule: false,
        outputPath: `static/imgs/`,
      }
    }]
  })
);
  1. 如需要配置eslint配置:
npm install react-app-rewired-eslint --save (yarn add react-app-rewired-eslint)
//在config-overrides.js 中修改如下:
const rewireEslint = require('react-app-rewired-eslint');
 
/* config-overrides.js */
module.exports = function override(config, env) {
  config = rewireEslint(config, env);
  return config;
}

再创建自己的.eslintrc文件,文件结构如下:

+-- your-project
|   +-- .eslintrc
|   +-- config-overrides.js
|   +-- node_modules
|   +-- package.json
|   +-- public
|   +-- README.md
|   +-- src



3.支持less

  1. 安装less,直接安装后,并不会生效,需要做系统配置,参考第3步
npm install less less-loader --save-dev (yarn add less less-loader --dev)

如果直接安装后,出现less-loader版本过高,导致编译报错的问题,可重新安装低版本

npm uninstall less-loader  --save-dev (yarn remove less-loader --dev)
npm install less-loader@6.0.0  --save-dev (yarn add less-loader@6.0.0 --dev)
  1. 如果采用react-app-rewired,less 生效配置如下:
const {
  override,
  addLessLoader
  // ...
} = require('customize-cra')

module.exports = override(
  // less
  addLessLoader({
    // 现在的写法
    lessOptions: {
      javascriptEnabled: true,
      // modifyVars: { '@brand-primary': '#1DA57A' },
      modifyVars: getLessVars(path.join(__dirname, './src/styles/vars.less')),
    },
    // 原来的写法
    // javascriptEnabled: true,
    // modifyVars: {
    //   '@primary-color': '#1DA57A',
    // },
    // localIdentName: '[local]--[hash:base64:5]' // 自定义 CSS Modules 的 localIdentName
  })
)

启动可能报错如下:

ValidationError: Invalid options object. PostCSS Loader has been initialized using an options object that does not match the API schema.
 - options has an unknown property 'plugins'. These properties are valid:
   object { postcssOptions?, execute?, sourceMap?, implementation? }
ERROR in ./src/pages/login/login.less (./node_modules/css-loader/dist/cjs.js??ruleSet[1].rules[1].oneOf[9].use[1]!./node_modules/postcss-loader/dist/cjs.js??ruleSet[1].rules[1].oneOf[9].use[2]!./node_modules/resolve-url-loader/index.js??ruleSet[1].rules[1].oneOf[9].use[3]!./node_modules/less-loader/dist/cjs.js??ruleSet[1].rules[1].oneOf[9].use[4]!./src/pages/login/login.less)
Module build failed (from ./node_modules/postcss-loader/dist/cjs.js):
ValidationError: Invalid options object. PostCSS Loader has been initialized using an options object that does not match the API schema.
 - options has an unknown property 'plugins'. These properties are valid:
   object { postcssOptions?, execute?, sourceMap?, implementation? }
    at validate (D:\developer\workspace\micro\micro-react\node_modules\webpack\node_modules\schema-utils\dist\validate.js:105:11)
    at Object.getOptions (D:\developer\workspace\micro\micro-react\node_modules\webpack\lib\NormalModule.js:585:19)
    at Object.loader (D:\developer\workspace\micro\micro-react\node_modules\postcss-loader\dist\index.js:40:24)

webpack compiled with 1 error

解决思路,在config-overrides.js文件增加如下内容:

const {
  override,
  adjustStyleLoaders,
  //...
 }
adjustStyleLoaders(({ use: [, , postcss] }) => {
    const postcssOptions = postcss.options;
    postcss.options = { postcssOptions };
  }),



4. 支持scss/sass

  1. 安装sass
npm install node-sass sass-loader --save-dev (yarn add node-sass sass-loader --dev)

安装完成后就可以直接使用,如xxx.jxs文件中:

// 导入scss文件
import '@/assets/css/login.scss';
...
<div className="login">
  1. 要配置全局scss/sass文件,如果采用react-app-rewired,配置如下:
npm install  sass-resources-loader --save-dev (yarn add sass-resources-loader --dev)
const {
  override,
  adjustStyleLoaders
  // ...
} = require('customize-cra')

module.exports = override(
adjustStyleLoaders(rule => {
    if (rule.test.toString().includes("scss")) {
      rule.use.push({
        loader: require.resolve("sass-resources-loader"),
        options: {
          resources: "./src/assets/css/base.scss" //这里是你自己放公共scss变量的路径
        }
      })
    }
  })
)



5. 安装element-ui

// 安装
npm i element-react --save (yarn add element-react)
// 下载主题包
npm install element-theme-default --save  (yarn add element-theme-default)

在 React 中使用

// 打开需要使用到 element-ui 的 jsx 文件,在头部添加
import React from 'react';
import ReactDOM from 'react-dom';
import { Button } from 'element-react';
import 'element-theme-default';

使用参考:

官方网站



6. 路由导航(常规使用)

npm install react-router-dom --save (yarn add react-router-dom)

安装完成后,直接可使用,过程中可能出现的错误如下:



编译出错

加入导航后,编译出错。



错误一
Module not found: Error: Can't resolve 'babel-runtime/helper/extends'

解决方案,安装babel-runtime解决

npm install babel-runtime --save (yarn add babel-runtime)


错误二
ERROR in ./node_modules/element-react/dist/npm/es5/src/tree/model/tree-store.js 32:90-117
Module not found: Error: Can't resolve 'react-hot-loader' in 'D:\developer\workspace\micro\micro-react\node_modules\element-react\dist\npm\es5\src\tree\model'

解决方案,安装react-hot-loader

npm install react-hot-loader --save (yarn add react-hot-loader)
react-hot-loader@^4.13.0 requires a peer of @types/react@^15.0.0 || ^16.0.0 || ^17.0.0  but @types/react@18.0.21 was installed

安装的最新版本只支持react 15.0|16.0| 17.0以上,由于采用react-create-app方式,安装的react版本为18.2.0,只能降低react版本为1.7.2

yarn remove react react-dom
yarn add react@17.0.2 react-dom@17.0.2


错误三

降低react版本后,又出现错误:

Module not found: Error: Can't resolve 'react-dom/client' in 'D:\developer\workspace\micro\micro-react\src'
LOG from webpack.FileSystemInfo
<w> Managed item D:\developer\workspace\micro\micro-react\node_modules\element-react isn't a directory or doesn't contain a package.json (see snapshot.managedPaths option)
+ 8 hidden lines
Failed to compile.

主要是由于17与18版本的语法不同导致的

可参考::

官方网站说明


主要修改主类index.js代码

// 18版本语法
import ReactDOM from 'react-dom/client';
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(<App />);
//17版本语法
import { render } from 'react-dom';
const container = document.getElementById('app');
render( <App />, container );

顺利启动。



错误四
import React from 'react';
import { Routes, Route, Route } from 'react-router-dom'
import Login from './pages/login/Login';
import Main from './pages/main/Main'

export default function App() {
  return (
    <React.Fragment>
      <div>我是功能页面</div>
      <Router>
        <Routes>
          <Route path='/login' element={<Login />} />
        </Routes>
      </Router>
    </React.Fragment>
  );
}

报错如下:

Uncaught TypeError: Cannot read properties of undefined (reading 'pathname')
    at Router (components.tsx:316:1)
    at renderWithHooks (react-dom.development.js:14985:1)
    at mountIndeterminateComponent (react-dom.development.js:17811:1)
    at beginWork (react-dom.development.js:19049:1)
    at HTMLUnknownElement.callCallback (react-dom.development.js:3945:1)
    at Object.invokeGuardedCallbackDev (react-dom.development.js:3994:1)
    at invokeGuardedCallback (react-dom.development.js:4056:1)
    at beginWork$1 (react-dom.development.js:23964:1)
    at performUnitOfWork (react-dom.development.js:22776:1)
    at workLoopSync (react-dom.development.js:22707:1)
react-dom.development.js:20085 The above error occurred in the <Router> component:
    at Router (http://localhost:3000/static/js/bundle.js:87862:15)
    at div
    at App

解决方法:

这里直接使用

Router

标签会出现上述问题,用

BrowserRouter

代替,问题没有了。

出现下列问题:

No routes matched location “/

需要添加 “/” 路径的路由即可。

export default function App() {
  return (
    <React.Fragment>
      <div>我是功能页面</div>
      <BrowserRouter>
        <Routes>
          <Route path='/' element={<Navigate to="/main" />} />
          <Route path='/main' element={< Main /> } />
          <Route path='/login' element={<Login />} />
        </Routes>
      </BrowserRouter>
    </React.Fragment>
  );
}



8. Serve插件(查看打包运行效果)

// 安装插件(全局安装)
npm install -g serve (yarn global add serve)
//查看版本
serve -v
// 构建项目
yarn build
// 启动
serve -s build

效果如下:

在这里插入图片描述



安装typescript支持


参考文档

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

参考:https://zhuanlan.zhihu.com/p/104771562

https://blog.csdn.net/weixin_43216105/article/details/108244032

https://juejin.cn/post/7073405036025348110

https://www.jianshu.com/p/352e33c56d55

http://wmm66.com/index/article/detail/id/165.html

https://blog.csdn.net/u010059669/article/details/122359412



版权声明:本文为freelb原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。