
一、开发前言
1. 规范

2. 创建项目
node -v => 18.0.0
npm -v => 8.6.0
create-react-app star-airbnb
3. 项目基本配置
配置jsconfig.json
{
  "compilerOptions": {
    "target": "es5",
    "module": "esnext",
    "baseUrl": "./",
    "moduleResolution": "node",
    "paths": {
      "@/*": [
        "src/*"
      ]
    },
    "jsx": "preserve",
    "lib": [
      "esnext",
      "dom",
      "dom.iterable",
      "scripthost"
    ]
  }
}通过craco配置
react脚手架隐藏webpack
解决一 : npm run eject
导出webpack配置,要去找到对应的配置,如果修改错误,项目可能跑不起来
解决二 : 通过craco => create-react-app config
配置后,会与原来的webpack配置混合
npm install @craco/craco@alpha -D => "react-scripts": "5.0.1"
新建 craco.config.js文件
/* package.json */
"scripts": {
-   "start": "react-scripts start",
-   "build": "react-scripts build",
-   "test": "react-scripts test",
+   "start": "craco start",
+   "build": "craco build",
+   "test": "craco test",
}别名
const path = require('path');
const resolve = (pathName) => path.resolve(__dirname, pathName);
module.exports = {
  // webpack
  webpack: {
    alias: {
      '@': resolve('src'),
      'assets': resolve('src/assets'),
      'components': resolve('src/components'),
      'view': resolve('src/view'),
      'store': resolve('src/store'),
      'utils': resolve('src/utils'),
      'router': resolve('src/router'),
      'services': resolve('src/services'),
      'baseUi': resolve('src/base-ui')
    }
  }
};
less文件
可查看 Ant Design 这里所用是4点多的版本
npm i craco-less@2.1.0-alpha.0
const path = require('path');
const resolve = (pathName) => path.resolve(__dirname, pathName);
const CracoLessPlugin = require('craco-less');
module.exports = {
  // less
  plugins: [
    {
      plugin: CracoLessPlugin,
      options: {
        lessLoaderOptions: {
          lessOptions: {
            // modifyVars: { '@primary-color': '#1DA57A' },
            javascriptEnabled: true
          }
        }
      }
    }
  ],
  // webpack
  webpack: {
    alias: {
      '@': resolve('src'),
      assets: resolve('src/assets'),
      components: resolve('src/components'),
      view: resolve('src/view'),
      store: resolve('src/store'),
      utils: resolve('src/utils'),
      router: resolve('src/router'),
      services: resolve('src/services'),
      baseUi: resolve('src/base-ui')
    }
  }
};css样式重置
对默认CSS样式进行重置
normalize.css
npm install normalize.css
import React from 'react';
import ReactDOM from 'react-dom/client';
import App from './App';
import 'normalize.css';
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
  <React.StrictMode>
    <App />
  </React.StrictMode>
);reset.css
@mainColor: #484848;
blockquote, body, button, dd, dl, dt, fieldset, form, h1, h2, h3, h4, h5, h6, hr, input, legend, li, ol, p, pre, td, textarea, th, ul {
  // color: @mainColor;
  padding: 0;
  margin: 0;
}
a {
  color: @mainColor;
  text-decoration: none;
}
img {
  vertical-align: top;
}
body {
  font-size: 14px;
  font-family: Circular, "PingFang-SC", "Hiragino Sans GB", "微软雅黑", "Microsoft YaHei", "Heiti SC" ;
  -webkit-font-smoothing: antialiased;
}目录结构划分

4. 主题配置
项目使用styled-components,可用于配置主题
配置
theme/index.js
export const theme = {
  color: {
    $primaryColor: '#FF385C',
    $secondaryColor: '#00848A',
    $textColor: '#484848',
    $textColorSecondary: '#222222'
  },
  fontSize: {
    $small: '12px',
    $normal: '14px',
    $large: '16px'
  },
  mixin: {
    $boxShadow: `
      transition: box-shadow 0.2s ease;
      &:hover {
        box-shadow: 0 2px 4px rgba(0,0,0,0.18);
      }
    `
  }
};
export default theme;
index.js
import React, { Suspense } from 'react';
import ReactDOM from 'react-dom/client';
import { HashRouter } from 'react-router-dom';
import { Provider } from 'react-redux';
// 1. 引入 Provider
import { ThemeProvider } from 'styled-components';
import App from './App';
import store from './store';
import 'normalize.css';
import 'assets/css/index.less';
import { theme } from './theme';
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
  <Provider store={store}>
    {/* 2. 使用主题 */}
    <ThemeProvider theme={theme}>
      <HashRouter>
        <Suspense fallback={<div>Loading...</div>}>
          <App />
        </Suspense>
      </HashRouter>
    </ThemeProvider>
  </Provider>
);组件使用
import styled from 'styled-components';
export const LeftWrapper = styled.div.attrs((props) => ({
  // 1. 使用主题, 通过 props.theme 获取主题
  $primaryColor: props.theme.color.$primaryColor,
  $secondaryColor: props.theme.color.$secondaryColor
}))`
  flex: 1;
  display: flex;
  align-items: center;
  /* 2. 使用,这里是用一个回调函数 */
  color: ${({ $primaryColor }) => $primaryColor};
  .log {
    cursor: pointer;
  }
`;5. 路由配置
npm install react-router-dom
router/index.js
import React, { lazy } from 'react';
import { Navigate } from 'react-router-dom';
const Home = lazy(() => import('view/home'));
const Entire = lazy(() => import('view/entire'));
const Detail = lazy(() => import('view/detail'));
const routes = [
  {
    path: '/',
    element: <Navigate to='/home' />
  },
  {
    path: '/home',
    element: <Home />
  },
  {
    path: '/entire',
    element: <Entire />
  },
  {
    path: '/detail',
    element: <Detail />
  }
];
export default routes;index.js
import React, { Suspense } from 'react';
import ReactDOM from 'react-dom/client';
import { HashRouter } from 'react-router-dom';
import App from './App';
import 'normalize.css';
import 'assets/css/index.less';
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
  <React.StrictMode>
    <HashRouter>
      <Suspense fallback={<div>Loading...</div>}>
        <App />
      </Suspense>
    </HashRouter>
  </React.StrictMode>
);
App.jsx
import React, { memo } from 'react';
import { useRoutes } from 'react-router-dom';
import routes from 'router';
const App = memo(() => {
  return (
    <>
      <div className='header'>header</div>
      <div className='main-contain'>{useRoutes(routes)}</div>
      <div className='footer'>footer</div>
    </>
  );
});
export default App;
6. redux状态管理配置
npm install @reduxjs/toolkit react-redux

store
modules
home.js
home.js => 使用rtk模式
import { createSlice } from '@reduxjs/toolkit';
const homeSlice = createSlice({
  name: 'home',
  initialState: {
    a: [1, 2, 3, 4]
  },
  reducers: {}
});
export default homeSlice.reducer;
entire文件夹
entire => 使用原生模式,所以有四个文件
reducer.js
const initialState = {
  b: [1, 2, 3, 4]
};
const reducer = (state = initialState, action) => {
  switch (action.type) {
    // case 'ADD_USER':
    //   return {
    //     ...state,
    //     [action.payload.id]: action.payload
    //   };
    default:
      return state;
  }
};
export default reducer;index.js
import reducer from './reducer';
export default reducer;index.js
import { configureStore } from '@reduxjs/toolkit';
import homeReducer from './modules/home';
// 直接使用原生的entire,也是一样的,因为createSlice就是对原生的一种封装而已
import entireReducer from './modules/entire';
const store = configureStore({
  reducer: {
    home: homeReducer,
    entire: entireReducer
  }
});
export default store;
index.js
import React, { Suspense } from 'react';
import ReactDOM from 'react-dom/client';
import { HashRouter } from 'react-router-dom';
import { Provider } from 'react-redux';
import App from './App';
import store from './store';
import 'normalize.css';
import 'assets/css/index.less';
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
  <React.StrictMode>
    <Provider store={store}>
      <HashRouter>
        <Suspense fallback={<div>Loading...</div>}>
          <App />
        </Suspense>
      </HashRouter>
    </Provider>
  </React.StrictMode>
);
7. 网络请求 - axios配置
npm install axios
requset
config.js
export const BASE_URL = 'http://xxxxxx';
export const TIME_OUT = 20000;
index.js
import axios from 'axios';
import { BASE_URL, TIME_OUT } from './config';
class StarRequest {
  constructor(baseURL, timeout) {
    this.instance = axios.create({
      baseURL,
      timeout
    });
    this.instance.interceptors.response.use(
      (res) => {
        return res.data;
      },
      (err) => {
        return err;
      }
    );
  }
  request(config) {
    return this.instance(config);
  }
  get(config) {
    return this.request({ ...config, method: 'get' });
  }
  post(config) {
    return this.request({ ...config, method: 'post' });
  }
}
const starRequest = new StarRequest(BASE_URL, TIME_OUT);
export default starRequest;
index.js
import starRequest from './request';
export default starRequest;简单使用
import React, { memo, useEffect, useState } from 'react';
import starRequest from '@/services';
const Home = memo(() => {
  // 定义状态
  const [highscore, sethighscore] = useState({});
  // 请求
  useEffect(() => {
    starRequest.get({ url: '/home/highscore' }).then((res) => {
      console.log(res);
      sethighscore(res);
    });
  }, []);
  return (
    <>
      <div>Home</div>
      <div>{highscore.title}</div>
    </>
  );
});
export default Home;
二、注意事项
图片问题
导入需使用import | require 导入方可使用
不论是背景图片还是img使用图片
import导入
import styled from 'styled-components';
import coverPic from '@/assets/img/cover_01.jpeg';
export const BannerWrapper = styled.div`
  height: 529px;
  background: url(${coverPic}) center center/cover;
`;require导入
import styled from 'styled-components';
export const BannerWrapper = styled.div`
  height: 529px;
  background: url(${require('@/assets/img/cover_01.jpeg')}) center center/cover;
  
  /* 根据webpack版本不同,可能需要加default */
  /* background: url(${require('@/assets/img/cover_01.jpeg').default}) center center/cover; */
`;三、引入组件库
Material-Ui
安装
npm install @mui/material @mui/styled-engine-sc配置
const path = require('path');
const resolve = (pathName) => path.resolve(__dirname, pathName);
const CracoLessPlugin = require('craco-less');
module.exports = {
  // less
  plugins: [
    {
      plugin: CracoLessPlugin,
      options: {
        lessLoaderOptions: {
          lessOptions: {
            // modifyVars: { '@primary-color': '#1DA57A' },
            javascriptEnabled: true
          }
        }
      }
    }
  ],
  // webpack
  webpack: {
    alias: {
      '@': resolve('src'),
      assets: resolve('src/assets'),
      components: resolve('src/components'),
      view: resolve('src/view'),
      store: resolve('src/store'),
      utils: resolve('src/utils'),
      router: resolve('src/router'),
      services: resolve('src/services'),
      baseUi: resolve('src/base-ui'),
      // ++++++++++++++++
      '@mui/styled-engine': '@mui/styled-engine-sc'
    }
  }
};
Ant-Design
安装
npm install antd使用
// 直接组件中使用即可
import { Button } from 'antd';
<Button type='primary'>Button</Button>
四、项目效果
小视频



















