React18项目初始配置,别名和less,样式重置,Router,redux(RTK),axios封装

193 阅读3分钟

创建项目

create-react-app zm-airbnb

项目配置

  • 配置jsconfig.json
{
  "compilerOptions": {
    "target": "es5",
    "module": "esnext",
    "baseUrl": "./",
    "moduleResolution": "node",
    "paths": {
      "@/*": ["src/*"]
    },
    "jsx": "preserve",
    "lib": ["esnext", "dom", "dom.iterable", "scripthost"]
  }
}
  • 项目目录

image.png

别名

image.png

craco配置别名和less文件

npm i @craco/craco@alpha -D
创建craco.config.js文件

文件里配置:

const path = require("path");

const resolve = (pathname) => path.resolve(__dirname, pathname);

module.exports = {
  // less
  // webpack
  webpack: {
    alias: {
      "@": resolve("src"),
      components: resolve("src/components"),
      utils: resolve("src/utils"),
    },
  },
};

同时修改package.json里的scripts

  "scripts": {
    "start": "craco start",
    "build": "craco build",
    "test": "craco test",
    "eject": "react-scripts eject"
  }
  • 配置好后,npm start启动项目,会和webpack打包进行合并

配置less

"@craco/craco": "^7.0.0-alpha.9"版本

安装依赖npm i craco-less@2.1.0-alpha.0

const path = require("path");
const CracoLessPlugin = require("craco-less");

const resolve = (pathname) => path.resolve(__dirname, pathname);

module.exports = {
  // less
  plugins: [
    {
      plugin: CracoLessPlugin,
    },
  ],

  // webpack
  webpack: {
    alias: {
      "@": resolve("src"),
      components: resolve("src/components"),
      utils: resolve("src/utils"),
    },
  },
};
  • 修改了项目配置文件,需重启项目

测试less

@zmColor: blue;

body {
  color: @zmColor;
}
import React from "react";
import ReactDOM from "react-dom/client";
import App from "@/App";

import "./assets/css/index.less";

const root = ReactDOM.createRoot(document.getElementById("root"));
root.render(
  <React.StrictMode>
    <App />
  </React.StrictMode>
);

image.png 没问题,🆗

css样式的重置

  • npm i normalize.css
  • reset.less

image.png

@textColor: #484848;
@textColorSecondary: #222;
@import "./variables.less";

* {
  padding: 0;
  margin: 0;
}

a {
  color: @textColor;
  text-decoration: none;
}

img {
  vertical-align: top;
}

ul,
li {
  list-style: none;
}
@import "./reset.less";

引入webpack依赖图里

import React from "react";
import ReactDOM from "react-dom/client";
import App from "@/App";

import "normalize.css";
import "./assets/css/index.less";

const root = ReactDOM.createRoot(document.getElementById("root"));
root.render(
  <React.StrictMode>
    <App />
  </React.StrictMode>
);

项目路由Router的搭建和配置

npm i react-router-dom

  • 使用HashRouter
import React 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>
      <App />
    </HashRouter>
  </React.StrictMode>
);
  • 使用useRoutes()配置路由,在router目录下新建index.js文件,新建项目目录(home,entire,detail)
import React from "react";
import { Navigate } from "react-router-dom";

const Home = React.lazy(() => import("@/views/home"));
const Entire = React.lazy(() => import("@/views/entire"));
const Detail = React.lazy(() => import("@/views/detail"));

const routes = [
  {
    path: "/",
    element: <Navigate to="/home" />,
  },
  {
    path: "/home",
    element: <Home />,
  },
  {
    path: "/entire",
    element: <Entire />,
  },
  {
    path: "/detail",
    element: <Detail />,
  },
];
export default routes;

在App.jsx中导入 routes

import React, { memo } from "react";
import { useRoutes } from "react-router-dom";
import routes from "./router";

const App = memo(() => {
  return (
    <div className="app">
      <div className="header">header</div>
      <div className="page">{useRoutes(routes)}</div>
      <div className="footer">footer</div>
    </div>
  );
});
export default App;

设置Suspense,控制台不报错了

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>
    <Suspense fallback="loading">
      <HashRouter>
        <App />
      </HashRouter>
    </Suspense>
  </React.StrictMode>
);

redux的配置

安装依赖npm i @reduxjs/toolkit react-redux

image.png

store目录

image.png

import { configureStore } from "@reduxjs/toolkit";
import homeReducer from "./modules/home";
const store = configureStore({
  reducer: {
    home: homeReducer,
  },
});
export default store;
import { createSlice } from "@reduxjs/toolkit";
const homeSlice = createSlice({
  name: "home",
  initialState: {
    ikun: [],
  },
  reducers: {},
});
export default homeSlice.reducer;

Provider为组件提供store,

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 "normalize.css";
import "./assets/css/index.less";
import store from "./store";

const root = ReactDOM.createRoot(document.getElementById("root"));
root.render(
  <React.StrictMode>
    <Suspense fallback="loading">
      <Provider store={store}>
        <HashRouter>
          <App />
        </HashRouter>
      </Provider>
    </Suspense>
  </React.StrictMode>
);
  • 另外一种配置(reducer配置store) 目录:

image.png

const initialState = {
  originReducerReduxIkun: [],
};

function reducer(state = initialState, action) {
  switch (action.type) {
    default:
      return state;
  }
}
export default reducer;
                    index.js
import reducer from "./reducer";
export default reducer;
                                        store -> index.js
import { configureStore } from "@reduxjs/toolkit";
import homeReducer from "./modules/home";
import entireReducer from "./modules/entire";

const store = configureStore({
  reducer: {
    home: homeReducer,
    entire: entireReducer,
  },
});
export default store;

控制台查看state:

image.png

网络请求封装

npm i axios

image.png

services文件夹中写网络请求,目录如下:

image.png

                                       config.js
export const BASE_URL = "http://codercba.com:1888/airbnb/api";
export const TIMEOUT = 10000;
                                  request ->  index.js
import axios from "axios";
import { BASE_URL, TIMEOUT } from "./config";

class ZMRequest {
  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.request(config);
  }

  get(config) {
    return this.request({ ...config, method: "get" });
  }

  post(config) {
    return this.request({ ...config, method: "post" });
  }
}
const req = new ZMRequest(BASE_URL, TIMEOUT);
export default req;
                               services ->  index.js
import zmRequest from "./request";
export default zmRequest;

在组件中使用封装好的网络请求,从服务器获取数据

import zmRequest from "@/services";
import React, { memo, useEffect } from "react";
const Home = memo(() => {
  // 网络请求的代码
  useEffect(() => {
    zmRequest.get({ url: "/home/highscore" }).then((res) => {
      console.log(res);
    });
  }, []);
  return <div>Home</div>;
});
export default Home;

image.png

展示数据:

import zmRequest from "@/services";
import React, { memo, useEffect, useState } from "react";

const Home = memo(() => {
  // 定义状态
  const [highScore, setHighScore] = useState({});

  // 网络请求的代码
  useEffect(() => {
    zmRequest.get({ url: "/home/highscore" }).then((res) => {
      console.log(res);
      setHighScore(res);
    });
  }, []);
  return (
    <div>
      <h2>{highScore.title}</h2>
      <h4>{highScore.subtitle}</h4>
      <ul>
        {highScore.list?.map((item) => {
          return <li key={item.id}>{item.name}</li>;
        })}
      </ul>
    </div>
  );
});
export default Home;

image.png