创建React项目
◼ 创建项目的方式:create-react-app◼ 项目配置: 配置项目的icon 配置项目的标题 配置jsconfig.json新建jsconfig.json文件,在文件中粘贴以下内容{ "compilerOptions": { "target": "es5", "module": "esnext", "baseUrl": "./", "moduleResolution": "node", "paths": { "@/*": [ "src/*" ] }, "jsx": "preserve", "lib": [ "esnext", "dom", "dom.iterable", "scripthost" ] } }
◼ 通过craco配置别名和less文件:在 create-react-app 中使用 - Ant Design下载安装npm install @craco/craco
在craco.config.js中粘贴如下代码:
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") } } }
目录结构
CSS样式的重置
◼ 对默认CSS样式进行重置: normalize.css reset.css
全家桶 – Router配置
1. 新建router目录,并创建index.js:
- 创建路由映射表
- 做异步及重定向处理
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
2. 解决lazy 的问题
在入口 index.js 中从 react 引入Suspense 来解决lazy问题
import React, { Suspense } from 'react' import ReactDOM from 'react-dom/client' import { HashRouter as Router } from "react-router-dom"; import App from '@/App' import "normalize.css" import "@/assets/css/index.less" // @ => src: webpack // 问题: react脚手架隐藏webpack // 解决一: npm run eject // 解决二: craco => create-react-app config const root = ReactDOM.createRoot(document.getElementById('root')); root.render( <Suspense fallback="loading ..."> <Router> <App /> </Router> </Suspense> );
3.在入口组件App.jsx中使用
- 从react-router-dom中引入 useRoutes
- 导入写好的路由映射表
- 调用 useRoutes方法并传入路由映射表
import React, { memo } from 'react' import { useRoutes } from "react-router-dom"; import routes from "@/router"; const App = memo(() => { return ( <div className='app'> <header className='header'>header</header> <main className='page'> {useRoutes(routes)} </main> <footer className='footer'>footer</footer> </div> ) }) export default App
全家桶 – Redux状态管理
◼ Redux状态管理的选择: 普通方式:目前项目中依然使用率非常高; @reduxjs/toolkit方式:推荐方式, 未来的趋势;
安装:
RTK 默认安装了 redux
npm install @reduxjs/toolkit react-redux
使用RTK创建store
- 再store目录下的index.js文件引入RTK
- 使用RTK提供的 configureStore来创建
- 这里引入 homeReducer 和 entireReducer( 下面有说↓ )
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
再项目入口index.js中使用store
- 使用react-redux中 提供的Provider组件
- 引入上面写好的store
- 再Provider组件上写 store={store}
import React, { Suspense } from 'react' import ReactDOM from 'react-dom/client' import { HashRouter as Router } from "react-router-dom"; import { Provider } from "react-redux"; import store from "@/store" import App from '@/App' import "normalize.css" import "@/assets/css/index.less" // @ => src: webpack // 问题: react脚手架隐藏webpack // 解决一: npm run eject // 解决二: craco => create-react-app config const root = ReactDOM.createRoot(document.getElementById('root')); root.render( <Provider store={store}> <Suspense fallback="loading ..."> <Router> <App /> </Router> </Suspense> </Provider> );
reducer的创建:
1. homeReducer ( 使用RTK ):
- HomeReducer 使用RTK 提供的切片 createSlice 来创建
- 需要指定 name initialState(初始值) reducers
- 导出HomeSlice 下的 reducer
import { createSlice } from "@reduxjs/toolkit"; const homeSlice = createSlice({ name: "home", initialState: { }, reducers: { } }) export default homeSlice.reducer
2. entireReducer ( 普通写法 )
目录结构:
在reducer.js中 定义recuder:
const initialState = { } function reducer(state = initialState, action) { switch (action.type) { default: return state } } export default reducer
在index.js中引入并导出:
- 这里导出的是reducer,所以可以在store目录下的index.js中可以
import reducer from "./reducer"; export default reducer
网络请求 - axios
目录结构:
- axios二次封装这里采用 class 类的写法
- config.js中定义了 axios 的配置常量 ( 可往下看 )
- 定义 get 和 post请求方法
- 这里我加入了 进度条 ( 可不加 )
在request目录下的index.js中写如下代码:
import axios from "axios"; import { BASE_URL, TIMEOUT } from "./config"; import NProgress from "nprogress"; class HYrequest { constructor(baseURL, timeout) { this.instance = axios.create({ baseURL, timeout }) this.instance.interceptors.request.use(config => { NProgress.start() return config }) this.instance.interceptors.response.use(res => { NProgress.done() return res.data }, err => { console.log(err); return Promise.reject(err) }) } request(config) { return this.instance.request(config) } get(config){ return this.request({...config,method:'get'}) } post(config){ return this.request({...config,method:'post'}) } } export default new HYrequest(BASE_URL, TIMEOUT)
在config.js中写以下代码:
export const BASE_URL = "http://codercba.com:1888/airbnb/api" export const TIMEOUT = 10000
在外层index.js中引入 并导出:
import HYrequest from "./request/index"; export default HYrequest
在Home组件中尝试请求数据:
- 注意: 这里可忽略,只是尝试请求数据,之后使用 redux 管理
import React, { memo, useEffect, useState } from 'react' import hyRequest from "@/services"; const home = memo(() => { const [highScore, setHighScore] = useState({}) useEffect(() => { hyRequest.get({ url: "/home/highscore" }).then(res => { setHighScore(res) console.log(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