1、创建项目
npx create-react-app my-app
cd my-app
yarn start
配置src别名
运行命令 ,暴露 config
yarn eject
进入 webpack.config.js中,找到 alias 添加以下2行
// 文件路径别名
'@': path.resolve(__dirname, '../src'),
'@pages': path.resolve(__dirname, '../src/pages'),
2、引入路由(使用5版本)
yarn add react-router-dom@5
- 编写 AppRouter,包裹所有路由配置Route
import { HashRouter, BrowserRouter, Switch, Route, Redirect } from 'react-router-dom'
import routerMapping from './router-mapping';
function AppRouter(porps) {
// 权限过滤
const handleFilter = route =>{
// true 有权限,false 无权限
return true;
}
return (
<HashRouter>
<Switch>
<Redirect exact from="/" to="/home" />
{routerMapping.map((route) => {
return (
handleFilter(route) && (
<Route
component={route.component}
key={route.path}
path={route.path}
/>
)
);
})}
<Redirect to="/error/404" />
</Switch>
</HashRouter>
)
}
export default AppRouter;
- 编写 router-mapping.js
import Loadable from 'react-loadable';
import Loading from '@/components/Loading'
const Home = Loadable({loader: () => import(/*webpackChunkName:'Home'*/'@/pages/home'),loading: Loading});
const Error404 = Loadable({loader: () => import(/*webpackChunkName:'Home'*/'@/pages/error/404'),loading: Loading});
export default [
{ path: "/home", component: Home, roles: ["admin","editor","guest"] },
{ path: "/error/404", component: Error404, roles: ["admin","editor","guest"] },
]
- 编写菜单 router-menu-config.js
export const RouterMenuConfig = [
{
title: "首页",
path: "/home",
icon: "home",
roles:["admin","editor","guest"]
},
];
3、引入less
1、安装
yarn add less less-loader -S
2、webpack.config.js中
定义:
const lessRegex = /\.less$/;
const lessModuleRegex = /\.module\.less$/;
rule中
{
test: lessRegex,
exclude: lessModuleRegex,
use: getStyleLoaders(
{
importLoaders: 3,
sourceMap: isEnvProduction
? shouldUseSourceMap
: isEnvDevelopment,
modules: {
mode: 'icss',
},
},
'less-loader'
),
// Don't consider CSS imports dead code even if the
// containing package claims to have no side effects.
// Remove this when webpack adds a warning or an error for this.
// See https://github.com/webpack/webpack/issues/6571
sideEffects: true,
},
{
test: lessModuleRegex,
use: getStyleLoaders(
{
importLoaders: 3,
sourceMap: isEnvProduction
? shouldUseSourceMap
: isEnvDevelopment,
modules: {
mode: 'local',
getLocalIdent: getCSSModuleLocalIdent,
},
},
'less-loader'
),
},
3、重启项目
4、界面中应该就生效了
.home-container {
background-color: red;
.title {
color: #fff;
}
}
import react from 'react'
import './home.less'
export default function() {
return (
<div className="home-container">
<div className='title'>标题</div>
this is home page.
</div>
)
}
4、引入 sass
1、项目中应该有默认引入依赖了,package.json中
"sass-loader": "^12.3.0",
2、安装 node-sass
这里安装了:
“node-sass”: “^9.0.0”,
yarn add node-sass
5、引入 redux相关
yarn add redux react-redux redux-thunk
默认最新的安装的版本如下:
"react-redux": "^9.0.4",
"redux": "^5.0.1",
"redux-thunk": "^3.1.0",
- 1、创建全局 store
import { createStore, applyMiddleware } from 'redux'
import reduxThunk from 'redux-thunk'
import reducer from './reducers'
const store = createStore(reducer, applyMiddleware(reduxThunk));
export default store
- 2、创建 reducers
// app.js
import { ActionTypes } from "../action-types";
const initState = {
lang: 'zh',
}
export default function app(state = initState, action) {
switch(action.type) {
case ActionTypes.App.UPDATE_LANGE: {
return {
...state,
lang: action.lang
}
}
default:
return state;
}
}
// index.js
import { combineReducers } from "redux";
import app from './app'
export default combineReducers({
app
})
- 3、创建 actions
// app.js
import { ActionTypes } from "../action-types"
export const app_update_lang = lang =>{
return {
type: ActionTypes.App.UPDATE_LANGE,
lang: lang
}
}
- 4、创建 actions常量定义,文件夹:action-types
// action-types
export const ActionTypes = {
App: {
// 更新语言
UPDATE_LANGE: 'updateLange'
}
}
- 5、创建 controller (自定义的一个便捷控制层)
// StoreController // 用于 全局的
import { AppStoreController } from "./app-store-controller";
export class StoreController {
static dispatch = null;
static RegisterDispatch(dispatch) {
this._saveDispatch(dispatch)
}
static _saveDispatch(dispatch) {
if(dispatch) {
this.dispatch = dispatch;
AppStoreController.dispatch = dispatch;
}
}
}
// app-store-controller.js
import { app_update_lang } from "../actions/app";
export class AppStoreController {
static dispatch;
/**
* 更新语言
* @param {*} lang
*/
static UpdateLang(lang) {
this.dispatch(
app_update_lang(lang)
)
}
/**
* 更新语言到 en
*/
static UpdateLang_EN() {
this.UpdateLang("en")
}
/**
* 更新语言到 zh
*/
static UpdateLang_ZH() {
this.UpdateLang("zh")
}
}
- 5、连接状态
// App.js 入口文件中
import logo from './logo.svg';
import './App.css';
import MyRoute from './router'
import { Provider } from "react-redux";
import store from "./store";
function App() {
return (
// redux
<Provider store={store}>
<MyRoute />
</Provider>
)
}
export default App;
- 6、全局dispatch存储
可以在最顶层的 conncet文件中,获取到dispatch来存储
这里展示是 MyRoute中,因为这个是路由的入口文件,所以这个就是顶层的项目入口
// src\router\index.js
import { HashRouter, BrowserRouter, Switch, Route, Redirect } from 'react-router-dom'
import routerMapping from './router-mapping';
import { connect } from "react-redux";
import { useEffect, useState } from 'react';
import { StoreController } from '../store/controller';
function AppRouter(props) {
// 权限过滤
const handleFilter = route =>{
// true 有权限,false 无权限
return true;
}
useEffect(()=>{
if(props.dispatch) {
StoreController.RegisterDispatch(props.dispatch); // 保存 dispatch
console.log("保存 dispatch", props.dispatch);
}
}, [props.dispatch])
return (
<HashRouter>
<Switch>
<Redirect exact from="/" to="/home" />
{routerMapping.map((route) => {
return (
handleFilter(route) && (
<Route
component={route.component}
key={route.path}
path={route.path}
/>
)
);
})}
<Redirect to="/error/404" />
</Switch>
</HashRouter>
)
}
export default connect((state) =>{
return {
lang: state.app.lang
}
},dispatch =>{
return {
dispatch: dispatch, // 这里 dispatch 暴露进界面
}
})(AppRouter);
6、引入国际化库
Format.JS
文档:https://formatjs.io/docs/getting-started/installation
- 安装
yarn add react-intl
- 默认安装的版本:
"react-intl": "^6.5.5",
- 创建 i18n文件
import { FormattedMessage } from 'react-intl'
/*
id 对应的就是zh-CN.js中的配置的键值, 该组件的值就是键值对应的value
values 是 {},里面可以定义变量,示例如下
{name: '张三'}
- 如果文字里面是这样的: 我叫{name}
- 解析出来就是:我叫张三
defaultMessage id对应的key不存在时,这个是默认的值
*/
// 存储 i18n暴露的函数api intl
let I18nIntl = null;
export function setI18nIntl(val) {
// console.log("设置 i18n api: ", val);
I18nIntl = val;
}
/**
* react dom形式获取国际化
* @param {*} param0
* @returns
*/
export const I18nMessageDom = function({
id, values = {}, defaultMessage = ""
}) {
return (
<FormattedMessage
id={id}
values={values} // values 是 {},里面可以定义变量,示例如下
defaultMessage={defaultMessage}
/>
)
}
/**
* api形式获取国际化
* @param {*} param0
* @returns
*/
export const getI18nMessage = function({
id, values = {}, defaultMessage = ""
}) {
if(I18nIntl) {
return I18nIntl.formatMessage({
id, values, defaultMessage
});
}
return defaultMessage;
}
- 如果需要使用存储 api形式 intl函数的话,需要在入口文件中,使用高阶组件 injectIntl 包裹暴露出去
,在props中获取到intl
export default
// 这个是redux的
connect((state) =>{
console.log("state -->", state);
return {
lang: state.app.lang
}
},dispatch =>{
return {
dispatch: dispatch,
}
})(
// 这个是 i18n的,用于获取到 api式获取国际化的api函数:intl
injectIntl(LayoutMain)
);
7、引入组件库(Antd)
这里使用 antd + pro
yarn add antd @ant-design/pro-components
- 使用
import { Button } from 'antd'
return (
<div>
<div>
antd 示例
</div>
<Button type="primary">确定</Button>
<br/>
<br/>
<Button type="dashed">取消</Button>
</div>
)
|
|
|
|
END