React18+Vite+Ts+redux
生成一个vite+react+ts的项目
执行命令
npm create vite
选择react
选择 ts
cd vite-project
//安装依赖
npm install
//启动项目
npm run dev
ts以及vite的一些配置
根目录下的tsconfig.json配置ts
{
"compilerOptions": {
"target": "ES2020",//指定 ECMAScript 目标版本,如 "ES3", "ES5", "ES2015", "ES2020", 或 "ESNEXT"。默认为 "ES3"。
"useDefineForClassFields": true,
"lib": ["ES2020", "DOM", "DOM.Iterable"], // 编译过程或运行时需要引入的库文件的列表
"module": "ESNext",//指定模块代码生成的目标。常见选项有 "commonjs", "amd", "umd", "system", "es2015", "es2020", 或 "esnext"。默认为 "commonjs"。
"skipLibCheck": true,// 跳过所有声明文件的类型检查
/* Bundler mode */
"moduleResolution": "bundler",// 指定模块的解析策略
"allowImportingTsExtensions": true,
"resolveJsonModule": true, // 允许使用 .json 扩展名导入的模块
"isolatedModules": true,
"noEmit": true,// 不输出(意思是不编译代码,只执行类型检查
"jsx": "react-jsx",// 在 .tsx 文件里支持 JSX:"react" 或 "react-native"
/* Linting */
"strict": true,//启用所有严格类型检查
"noUnusedLocals": true,// 生成相应的.d.ts文件
"noUnusedParameters": true,// 报告未使用参数的错误
"noFallthroughCasesInSwitch": true,
"baseUrl": "./", /* 设置项目的基本路径*/
"paths": {
"@utils/*": ["src/utils/*"],
"@service/*": ["src/service/*"],
"@components/*": ["src/components/*"],
"@views/*": ["src/views/*"],
"@route/*": ["src/route/*"],
"@store/*": ["src/store/*"],
"@types/*": ["src/types/*"],
"@styles/*": ["src/styles/*"],
}, /* 重新映射包的相对路径 */
},
"include": ["src"],// *** TypeScript文件应该进行类型检查 ***
"references": [{ "path": "./tsconfig.node.json" }]
}
根目录下的vite.config.ts => Vite 的配置信息
import { defineConfig } from 'vite'
import react from '@vitejs/plugin-react'
import { resolve } from 'path'
// https://vitejs.dev/config/
export default defineConfig({
plugins: [react()],//插件
resolve: {//解析
alias: {//别名 这些别名在项目的代码中可以用作简化导入路径的方式
'@': resolve(__dirname, 'src'),
'@utils': resolve(__dirname, 'src/utils'),
'@service': resolve(__dirname, 'src/service'),
"@assets": resolve(__dirname, "src/assets"),
"@components": resolve(__dirname, "src/components"),
"@views": resolve(__dirname, "src/views"),
"@layout": resolve(__dirname, "src/layout"),
"@config": resolve(__dirname, "src/config"),
"@store": resolve(__dirname, "src/store"),
"@route": resolve(__dirname, "src/route"),
}
},
server: {
port: 3000,//端口号
proxy: {//代理
"/api": {
target: "https://",
changeOrigin: true,// 如果需要跨域,则设置为 true
cookieDomainRewrite: "",// 如果需要重写 cookie 域名,请填写相应的值
secure: false,// 如果您的代理服务器��持 HTTPS,可以设置为 true
},
},
}
})
redux
安装redux
Redux是一个JavaScript状态容器,为应用程序(特别是React应用程序)提供集中的状态管理。 对于小型或简单的应用程序,使用React的本地状态和props可能已经足够了。然而,随着应用程序的规模和复杂性的增加,Redux可以提供更多的好处和优势。
什么场景下适用redux?
- 全局状态管理:当你的应用程序中有一些状态需要在多个组件之间共享时,Redux是一个很好的选择。Redux提供了一个中心化的store来保存这些状态,并允许你通过actions和reducers来更新它们。
- 复杂的异步操作:Redux的middleware(如redux-thunk、redux-saga或redux-observable)可以帮助你处理复杂的异步操作。
- 大型或复杂的应用程序:对于大型或复杂的单页面应用程序,通过将所有状态保存在一个中心化的store中,你可以更容易地理解和调试应用程序的状态。
- 跨组件通信:Redux允许你在不直接相关的组件之间传递数据。通过使用Redux的
actions
和reducers
,你可以将数据从一个组件发送到另一个组件,而无需将它们直接链接在一起或使用复杂的父子组件传递。
核心
- reducer 接收当前的应用状态和一个动作(action),然后返回一个新的状态。Reducers是纯函数,对于相同的输入总是返回相同的输出。
- action Actions是事件,它们传递来自应用程序(如用户接口、内部事件如API调用和表单提交)的数据给store。Actions是简单的具有一个type属性(通常是常量)的JavaScript对象,这个对象描述了action的类型以及传递给store的负载信息。
- storeStore是Redux应用程序中单一的状态容器。它保存了整个应用程序的状态,并且这个状态不能直接被改变。当一些数据变化时,一个新的对象就会被创建(使用actions和reducers)。
npm i react-router-dom redux react-redux redux-thunk
创建store
在根目录下的store文件夹创建index.ts文件
// src/store/index.js
import { createStore, applyMiddleware } from "redux";
// 用于支持异步action
import thunk from "redux-thunk";//这个中间件允许你在 action 创建函数中返回函数,以实现异步逻辑。
import reducers from "./reducer";
export default createStore(reducers, applyMiddleware(thunk))
创建reducer
在store文件夹下创建reducer文件夹
//src/store/reducer/nameReducer.ts
import { SET_AGE, SET_NAME } from "../constants";
const nameState = {
name: "岚岚同学",
age: 18,
};
export const nameReducer = (state = nameState, action : any) => {
const {type,data,payload} = action
switch (type) {
case SET_AGE:
return {
...state,
age: state.age + payload,
};
case SET_NAME:
return {
...state,
name: data,
};
default:
return state;
}
}
合并reducer
//src/store/reducer/index.ts
import { combineReducers } from "redux";
import { nameReducer } from "./nameReducer";
export default combineReducers({
nameReducer,
});
创建action
在store下创建actions文件夹
//src/store/actions/nameAction.ts
import { SET_AGE, SET_NAME } from '../constants'
export const setAge = function (age) {
return {
type: SET_AGE,
payload:age
};
};
export const setName = function (name:string) {
return {
type: SET_NAME,
data: name,
};
};
/* export const getList = () => {
return async (dispatch) => {
const { data } = await get_list();
dispatch({
type: "GET_LIST",
payload: data[0]
})
}
} */
constants.ts文件,用于定义action中的type,唯一性
//src/store/constants.ts
export const SET_AGE = "set_age";
export const SET_NAME = "set_name";
使用 Provider 包裹你的应用
Provider
组件由 Redux 的 React 绑定库 react-redux
提供。在 React 应用的最顶层,你需要使用 Provider
组件来包裹你的应用。这将使 Redux store 在整个组件树中可用。
//main.tsx
import React from 'react'
import ReactDOM from 'react-dom/client'
import App from './App.tsx'
import './index.css'
import { Provider } from "react-redux";
import store from './store'
ReactDOM.createRoot(document.getElementById('root')!).render(
// <React.StrictMode>
<Provider store={store}>
<App />
</Provider>
// </React.StrictMode>,
)
在组件中使用store
在组件中通过useSelector
来获取store中的状态,通过useDispatch
来获取action中的方法
//src/views/About.tsx
import { useState } from "react";
import { useSelector, useDispatch } from "react-redux";
import { setAge, setName } from '../store/actions/nameAction'
import { stateType } from "@types/about.type.ts";
// import '../scss/about.scss'
function About() {
const dispatch = useDispatch()
const name = useSelector((state:stateType) => state.nameReducer.name)
const age = useSelector((state:stateType) => state.nameReducer.age)
const [val, changeVal] = useState('')
const changeValue = (e) => {
const text = e.target.value
changeVal(text)
}
const changeName = () => {
dispatch(setName(val))
}
const changeAge = () => {
dispatch(setAge(1))
}
return (
<div className="about">
<div>
<p>名字是:{name}</p>
<input type="text" onChange={changeValue} />
<button onClick={changeName}>修改姓名</button>
<p>年龄是:{age}</p>
<button onClick={changeAge}>+1</button>
</div>
</div>
);
}
export default <About/>;
react-router
react-router
用于处理客户端路由
安装react-router
npm i react-router-dom
设置路由表
// src/route/index.ts
import LayoutCom from '../components/Layout'
import Home from '../views/Home'
import About from '../views/About'
const routes = [
{
path: '/',
element: LayoutCom,
children: [
{
path: '/home',
element: Home,
name: '首页',
},
{
path: '/about',
element: About,
name: '关于',
},
]
}
]
export default routes
配置路由
在APP中正确配置路由
import { useRoutes } from 'react-router-dom';//用于接收一个路由配置对象,并返回与当前URL路径对应的React组件。
import routes from '@route/index'; //引入路由
import { ConfigProvider } from 'antd';//全局化配置
import zhCN from 'antd/es/locale/zh_CN'; //国际化配置中文
import dayjs from 'dayjs';
import 'dayjs/locale/zh-cn';
import 'antd/dist/reset.css';
dayjs.locale('zh-cn');
const App = () => <ConfigProvider locale={zhCN}>{useRoutes(routes)}</ConfigProvider>
export default App;
使用BrowserRouter
将路由集成到应用中
// main.tsx
import { StyleProvider, legacyLogicalPropertiesTransformer } from '@ant-design/cssinjs'
// import ReactDOM from 'react-dom'; // react18不支持这样引入ReactDOM
import { createRoot } from 'react-dom/client';
import { BrowserRouter } from 'react-router-dom'; // 利用了 HTML5 History API 来实现路由切换。BrowserRouter 创建的 URL 看起来就像常规的 URL,没有额外的字符或哈希(#)
import { Provider } from "react-redux";//通过 React 的 context API 将 Redux store 传递给整个组件树
import store from './store' // 引入store
import App from './App.tsx'
import './index.css'
const root = createRoot(document.getElementById('root')!);
root.render(
<Provider store={store}>
<BrowserRouter>
<StyleProvider hashPriority="high" transformers={[legacyLogicalPropertiesTransformer]}>
<App />
</StyleProvider>
</BrowserRouter>
</Provider>
);
配置完成仓库以及路由以后就可以正常访问页面,使用redux了。
这时候访问 http://127.0.0.1:3000/home 就可以看到下方的页面了
转载自:https://juejin.cn/post/7379252155339489290