使用create-react-app搭建项目,默认隐藏webpack文件,引入less需要把配置文件暴露出来,操作如下:
npm run eject
注:此操作不可逆,一旦暴露不可回退。
1.wepack 配置了less(webpck版本:^5.64.4)
npm install less less-loader --save-dev
在webpack.config.js文件头部定义less正则:
const lessRegex = /\.less$/;
const lessModuleRegex = /\.module\.less$/;
const lessGlobalUrl = "./../src/*****.less";
查找module,在module.rules里添加以下代码:
{
test: lessRegex,
exclude: cssModuleRegex,
use: [
...getStyleLoaders(
{
importLoaders: 3,
sourceMap: isEnvProduction
? shouldUseSourceMap
: isEnvDevelopment,
},
'less-loader'
),
{
loader: 'style-resources-loader',
options: {
patterns: path.resolve(__dirname, lessGlobalUrl),
},
},
],
sideEffects: true,
},
2.配置代理
安装中间件npm install http-proxy-middleware --save-dev
在src下新建文件:setupProxy.js,与App.js同级,简单配置如下:
const { createProxyMiddleware } = require('http-proxy-middleware');
const baseURL = "http://xxxxx.com";//要指向的服务器地址
module.exports = function (app) {
app.use(
createProxyMiddleware(
'/api',
{
target: baseURL,
changeOrigin: true
}
)
)
}
axios文件改指向:
axios.create({
// baseURL: (process.env.NODE_ENV === 'production' ? baseURL : '') + 'api',
baseURL: 'api',
headers: {
},// 定义统一的请求头部
timeout: 10000, // 配置请求超时时间
withCredentials: true, // 如果用的JSONP,可以配置此参数带上cookie凭证,如果是代理和CORS不用设置
});
运行控制台报警告
image.png
虽然不影响热加载,但观感不好,解决方法如下:
找到webpackDevServer.config.js文件,把onBeforeSetupMiddleware和onAfterSetupMiddleware这两个方法替换成下面代码:
setupMiddlewares: (middlewares, devServer) => {
if (!devServer) {
throw new Error("webpack-dev-server is not defined");
}
middlewares.unshift({
name: 'evalSourceMapMiddleware',
middleware: evalSourceMapMiddleware(devServer),
});
if (fs.existsSync(paths.proxySetup)) {
// This registers user provided middleware for proxy reasons
require(paths.proxySetup)(devServer.app);
}
middlewares.push({
name: 'redirectServedPath',
middleware: redirectServedPath(paths.publicUrlOrPath),
});
middlewares.push({
name: 'noopServiceWorkerMiddleware',
middleware: noopServiceWorkerMiddleware(paths.publicUrlOrPath),
});
return middlewares;
}
3.useEffect重复调用的问题
解决方法:关闭严格模式,原因如下:
mmexport1681522623443.png
4.别名设置
webpack.config.js文件,找到modules.webpackAliases位置,配置示例如下:
'@api': path.resolve(__dirname, '../src/api'),
'@assets': path.resolve(__dirname,'../src/assets'),
'@components': path.resolve(__dirname,'../src/components'),
'@constants': path.resolve(__dirname, '../src/constants'),
'@containers': path.resolve(__dirname,'../src/containers'),
'@reducers': path.resolve(__dirname,'../src/reducers'),
'@request': path.resolve(__dirname,'../src/request'),
'@router': path.resolve(__dirname, '../src/router'),
'@utils': path.resolve(__dirname,'../src/utils'),
'@store': path.resolve(__dirname,'../src/store')
5.路由配置
路由菜单文件:
import Home from '@containers/Home'
import BasicLayout from '@containers/BasicLayout'
import Search from '@containers/Search';
// index 不能设置子路由,会报错
let routes = [
{
path: "/",
element: <BasicLayout />,
children: [
{ index: true, element: <Home /> },
{
path: "/search",
element: <Search />
}]
}
]
export default routes;
App.js文件引入路由:
import React from 'react';
import { useRoutes } from 'react-router-dom'//新增
import router from '@router/router';
function App() {
let element = useRoutes(router)//新增
return (
<div className='App'>
{element}
</div>
);
}
export default App;
主文件入口index.js渲染节点:
import React from 'react';
import ReactDOM from 'react-dom/client';
import {BrowserRouter} from 'react-router-dom'
import App from './App.js';
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
// 开启严格模式会双重渲染
// <React.StrictMode>
<BrowserRouter>
<App />
</BrowserRouter>
// </React.StrictMode>
);
6.路由跳转
注:不能定义在里层方法函数或者事件响应函数内,会报错,只能定义在主体函数里
Invalid hook call. Hooks can only be called inside of the body of a function component.
常用的跳转方法:
import { useNavigate,useSearchParams,} from 'react-router-dom';
const navigate = useNavigate()
//第一种:search传递参数
navigate('/search?text=333')
//获取方法:用useSearchParams来获取
const [getSearchArr] = useSearchParams();
//第二种:params传递参数,路由也需要占位符配置
navigate('/article/17');
//获取方法:用useParams来获取
const getParams = useParams();
//第三种:state属性携带参数
navigate('/search',{state: '测试'})
//获取方法:用useLocation来获取
const currentLocation = useLocation();
//获取url参数
const [params] = useSearchParams(); //获取url参数
params.get('text');//获取
params.set('');//设置
//获取location
const location = useLocation();
console.log(location.pathname);
7.useState 更新异步的问题
场景:使用 useState 储存,当去改变这个数据的时候,每次拿到的都是上次的数据,无法实时更新。使用setTimeout延迟回调也失效。
原因:useState 返回的更新对象的方法是异步的,要在下次重绘才能获取新值,不要试图在更改状态之后立即获取状态。setState 只在合成事件和钩子函数中是“异步”的,在原生事件和setTimeout 中都是同步的。
解决方法:
1.使用useRef存储,useRef不仅可以用于访问 DOM 节点,也可以用来表示一个容器,current属性可以保存任何值,而且useRef返回的对象会在整个生命周期内保持。useRef 可以存储那些不需要引起页面重新渲染的数据。
const [info, setInfo] = useState()
const infoRef = useRef()
useEffect(() => {
infoRef.current = info
}, [info])
2.重新定义一个数组来修改,在原数组上的修改不会引起组件的重新渲染,React 组件的更新机制对只进行浅对比,也就是更新某个复杂类型数据时只要它的引用地址没变,就不会重新渲染组件
const pushData = () => {
setArr([...arr, 4])
}
注:函数组件中是不能通过异步来获取更新的值
useState和useRef区别: useState会触发重新渲染,useRef不会被重新声明,相当于this.xxx,render时机不应该更新ref.curent; useState是异步更新的,useRef是同步的;变量则是每次组件重新渲染的时候都会被重新进行赋值,要保留之前的操作状态就不要使用变量
3.useEffect监听值变化再触发回调,相当于componentDidUpdate
useEffect(() => {
if (category ) {
// 调用搜索接口
handleSearch();
}
}, [category])
8.路由懒加载,使用react自带的api
import { lazy } from "react";
const BasicLayout = lazy(() => import("@containers/BasicLayout"));
const Home = lazy(() => import("@containers/Home"));
let routes = [
{
path: "/",
element: <BasicLayout />,
children: [
{ index: true, element: <Home /> }
]
}
];
根元素一定要加上Suspense,不然会报错,Error: A React component suspended while rendering, but no fallback UI was specified.
import React,{Suspense} from 'react';
import { useRoutes } from 'react-router-dom'//新增
import router from '@router/router';
import { ConfigProvider,Spin } from 'antd';
import locale from 'antd/locale/zh_CN';
function App() {
let element = useRoutes(router)//新增
return (
// 更改antd主题色
<ConfigProvider locale={locale} theme={{
token: {
colorPrimary: '#22986E',
},
}}>
<Suspense fallback={<Spin />}>
<div className='App'>
{element}
</div>
</Suspense>
</ConfigProvider>
);
}
网友评论