一、初始化项目(create-react-app)
create-react-app 项目名
二、配置别名(alias)
1、安装依赖
yarn add customize-cra react-app-rewired --save-dev
2、根目录创建config-overrides.js文件,注意名字不要写错,内容如下
const { override, addDecoratorsLegacy, addWebpackAlias } = require("customize-cra");
const path = require("path");
module.exports = override(
addDecoratorsLegacy(),
addWebpackAlias({
"@": path.resolve(__dirname, './src')
})
);
3、修改package.json的scripts部分,如下
"scripts": {
"start": "react-app-rewired start",
"build": "react-app-rewired build",
"test": "react-app-rewired test",
"eject": "react-app-rewired eject"
}
三、配置反向代理(http-proxy-middleware)
yarn add http-proxy-middleware
在src目录下创建 setupProxy.js 文件
// setupProxy.js
const { createProxyMiddleware } = require('http-proxy-middleware')
module.exports = function (app) {
app.use(createProxyMiddleware('/api', {
target: 'http://152.136.185.210:4000',
secure: false,
changeOrigin: true,
pathRewrite: {
"^/api": ""
}
}))
}
四、引入样式( scss / less / style-component )
scss
npm install sass-loader node-sass --save-dev
npm install --save-dev sass-resources-loader 在用scss预处理器的时候,会常用变量/函数/混合等功能。目前如果想要使用变量/函数的话需要在每个文件中单独引入,这样明显不合理,我们需要的是引入一次,所以我们就需要定义全局主题的样式变量,也就是利用sass-resources-loader这个loader将scss变量打包到每个文件中。首先我们要安装sass-resources-loader。
//在项目根目录,也就是和package.json同级创建config-overrides.js文件,该文件配置代码如下:
const { override, adjustStyleLoaders } = require("customize-cra");
module.exports = override(
// ...其他配置...
adjustStyleLoaders(rule => {
if (rule.test.toString().includes("scss")) {
rule.use.push({
loader: require.resolve("sass-resources-loader"),
options: {
resources: "./src/assets/scss/output.scss" //这里是你自己放公共scss变量的路径
}
});
}
})
);
styled-components
npm install styled-components
新建一个专门负责样式的 style.js 文件
import styled , { ThemeProvider } from 'styled-components'
ThemeProvider
是最外层的样式组件
<ThemeProvider theme={{themeColor : "red"}}>
<Children/>
<ThemeProvider/>
可以用来提供主题。在子组件中通过 ${props => props.theme.themeColor} 访问
五、引入请求模块(axios)
yarn add axios
六、引入路由模块(react-router-dom)
yarn add react-router-dom
import { Link , NavLink , withRouter , Route, Switch , BrowserRouter ,withRouter } from 'react-router-dom'
1. <BrowserRouter> history路由
2. <HashRouter> hash路由
3. <Route> 跳转路由 path="路径",component={组件}
4. <Redirect> 重定向 to="路径"
5. <Link> 跳转标签
6. <NavLink> 高亮跳转标签 添加 active 类名
7. <Switch> 选中一个后停止匹配,用于优化
8. withRouter函数 将非路由组件转换为路由组件,使其能够编程式跳转路由 withRouter(组件)
入口文件必须制定路由模式,并包裹组件或其祖宗组件才能使用
内置组件
1.编程式跳转
1. history对象 函数式组件需在函数参数声明形参props后,通过props可以拿到这些对象参数
2. match对象 获取query
3. location对象 locations.pathname 可以拿到当前路径
其它对象
注:若不是路由组件,需使用withRouter()函数进行包装成路由组件
import React from 'react'
import { Switch, Route, Redirect,withRouter } from 'react-router-dom'
export default function Discover(props) {
function changeRouter(path) {
if (props.location.pathname !== path) {
props.history.push(path)
}
}
return <div>
<button
style={{
color: pathname === '/home/recommend' ? 'red' : null,
}}
onClick={(e) => changeRouter('/home/recommend')}
>
点击我跳转推荐页
</button>
</div>
}
2.动态路由参数
params传的参数是暴露在url中的 // 且后代路由都会接收到该参数 // 主
需要 先声明 后注册传递参数
注册声明 <Route path=' /sort/:id ' component={Sort}></Route>
传递参数 this.props.history.push( '/sort/'+'2' )、
取值 props.match.params.id(函数式组件)
state传的参数是加密的 // 且后代路由不会接收到该参数, 重要的一点 : 刷新也可以保持住参数 // 主
无需声明,直接注册使用即可
传递参数 props.history.push({ pathname: path, state: { name: '孙悟空' } })
取值 props.location.state.name(函数式组件)
search(query) 需要解析,所以略过 // 且后代路由都会接收到该参数
无需声明,直接注册使用即可
传递参数 props.history.push({ pathname, query: { name: ' sunny' } })
取值 this.props.location.query.name
七、路由集中管理(react-router-config)
yarn add react-router-config
import { renderRoutes } from 'react-router-config';
//renderRoutes 可以配置 路由管理映射
//子路由通过组件内的 const { route } = props 拿到当前路由对象, 然后通过api renderRoutes(route.routes)
import React from 'react';
import { Redirect } from "react-router-dom";
import Discover from "../../src/components/centerMain/discover"
import Recommend from "../components/centerMain/discover/recommend"
const routes = [
{
path: "/",
exact: true,
render: () => (
<Redirect to="/discover"/>
)
},
{
path: "/discover",
component: Discover,
routes: [
{
path: "/discover",
exact: true,
render: () => (
<Redirect to="/discover/recommend"/>
),
},
{
path: "/discover/recommend",
component: Recommend
}]
}
]
export default routes;
在根组件中使用
import React, { memo , Suspense } from 'react'
import { renderRoutes } from 'react-router-config';
import { Provider } from "react-redux"
import TopBar from "./components/topBar/index.js"
import Player from "./components/player/index.js"
import HYAppFooter from '../src/components/bottomBar';
import routes from './router';
import store from '../src/store'
import './assets/css/base.css'
import 'antd/dist/antd.css'; // or 'antd/dist/antd.less'
import { HashRouter } from 'react-router-dom';
export default memo(function App() {
return (
<Provider store={store}>
<HashRouter>
<TopBar></TopBar>
<Suspense fallback={<div>page loading</div>}>
{renderRoutes(routes)}
</Suspense>
<HYAppFooter/>
<Player/>
</HashRouter>
</Provider>
)
})
八、引入全局状态管理工具(redux)
yarn add redux react-redux redux-thunk // redux 全局状态管理工具 // react-redux 将react和redux连接起来 // redux-thunk 用于异步操作
九、引入antd组件库
1.安装依赖
npm install antd --save
yarn add antd
2.引入样式
import 'antd/dist/antd.css'; // or 'antd/dist/antd.less'
3.在需要使用的页面中引入antd组件
import { DatePicker } from 'antd';
Form
const [form] = Form.useForm() //可以拿到表单实例
form.setFieldsValue({ name: 'Hi there!' })// 可以设置表单对应字段的值 可以输入多个字段
form.resetFields() //重置表单
安装脚手架(react-cli)
cmd : 1.更换npm源 npm config set registry https://registry.npm.taobao.org 2.检查是否更换成功 npm config get registry //如果显示 https://registry.npm.taobao.org 该地址就表示配置成功了 3.全局安装 react 脚手架 cnpm install -g create-react-app 4.创建react脚手架项目 create-react-app + 项目文件夹名称 5.启动项目 npm start 6.打包项目 npm build
引入eslint
一、
安装vscode插件
EditorConfig for VS Code
根目录添加文件
// .editorconfig # http://editorconfig.org root = true [*] # 表示所有文件适用 charset = utf-8 # 设置文件字符集为 utf-8 indent_style = space # 缩进风格(tab | space) indent_size = 2 # 缩进大小 end_of_line = lf # 控制换行类型(lf | cr | crlf) trim_trailing_whitespace = true # 去除行首的任意空白字符 insert_final_newline = true # 始终在文件末尾插入一个新行 [*.md] # 表示仅 md 文件适用以下规则 max_line_length = off trim_trailing_whitespace = false
二、
VSCode需要安装Prettier - Code formatter的插件
npm install prettier -D
配置.prettierrc文件:
{
"useTabs": false, //使用tab缩进还是空格缩进,选择false;
"tabWidth": 2, // tab是空格的情况下,是几个空格,选择2个;
"printWidth": 80, //当行字符的长度,推荐80,也有人喜欢100或者120;
"singleQuote": true, //使用单引号还是双引号,选择true,使用单引号;
"trailingComma": "none", //在多行输入的尾逗号是否添加,设置为 `none`;
"semi": false //语句末尾是否要加分号,默认值true,选择false表示不加;
}
配置.prettierignore忽略文件
/dist/* .local .output.js /node_modules/** **/*.svg **/*.sh /public/*
在package.json中配置一个scripts:
"prettier": "prettier --write ."
三、ESLint
VSCode需要安装ESLint插件
npm i eslint-plugin-prettier eslint-config-prettier -D
在package.json中配置extend:
extends: [ "eslint:recommended", "plugin:prettier/recommended" ],
dva.js
安装脚手架
npm install dva-cli -g
创建项目
dva new dva-quickstart
全局状态管理dva
import {routerRedux} from 'dva/router'
// routerRedux 可以实现在状态管理下进行路由跳转
// 类似vuex模式
export default {
//命名空间
namespace: 'example',
// 状态
state: {},
// 初始化会执行
subscriptions: {
setup({ dispatch, history }) { // eslint-disable-line
},
},
// 相当于 vuex中action
// payload 执行dispatch时传过来的参数
// call是执行函数的方法
// put 相当于 dispatch
effects: {
*fetch({ payload }, { call, put }) { // eslint-disable-line
yield put({ type: 'save' });
},
},
// 相当于 vuex中mutation
reducers: {
save(state, action) {
return { ...state, ...action.payload };
},
},
};
新的状态子模块需要在index.js入口文件中引入
app.model(require('./models/example').default);
umi.js
yarn create @umijs/umi-app
dva状态管理
根模块 1.在src目录下新建 models 文件夹,新建一个js文件。文件名就是根模块状态名 子模块 1.在src/pages/Home目录下新建 models 文件夹,新建一个js文件。文件名就是分模块状态名
模块文件js,书写如下
export default {
state: {
name: '王洪元',
},
effects: {
*getUserInfoAction({ payload }: any, { call, put }: any) {
yield put({ type: 'changeUserInfo', payload });
console.log(payload);
},
},
reducers: {
changeUserInfo(state: any, action: any) {
return {
...state,
name: action.payload,
};
},
},
};
组件中使用
import React from 'react';
import { connect } from 'dva';
const Home = ({ dispatch, rootUserName, homeUserName }: any) => {
const handleChangeUserInfo = () => {
dispatch({ type: 'global/getUserInfoAction', payload: '上古鬼' });
};
const handleChangeHomeUserInfo = () => {
dispatch({ type: 'home/getUserInfoAction', payload: 'masjdge' });
};
return (
<div>
<div>
<span>根姓名:{rootUserName}</span>
</div>
<div>
<span>home姓名:{homeUserName}</span>
</div>
<div>
<button onClick={handleChangeUserInfo}>根模块点击更改名字</button>
<button onClick={handleChangeHomeUserInfo}>子模块点击更改名字</button>
</div>
</div>
);
};
const mapStateToProps = (state: any) => {
return {
rootUserName: state.global.name,
homeUserName: state.home.name,
};
};
export default connect(mapStateToProps)(Home);
运行时配置
//执行顺序
render > patchRoutes
// 往路由表中向前增加一条路由映射
export function patchRoutes({ routes }: any) {
console.log(routes);
routes[0].routes.unshift({
path: '/foo',
exact: true,
title: '蕉叶',
component: require('@/pages/Home/index').default,
});
routes[0].routes.unshift({
path: '/',
exact: true,
redirect: '/home',
});
}
// 比如用于渲染之前做权限校验,
// 覆写 render。
export function render(oldRender: any) {
// console.log('中间件。路由在刷新前可以做一些事哦');
console.log(123);
oldRender();
}
// 在初始加载和路由切换时做一些事情。
export function onRouteChange({ location, routes, action, matchedRoutes }) {
// 动态修改网页标题
if (matchedRoutes.length) {
document.title = matchedRoutes[matchedRoutes.length - 1].route.title || '';
}
}
// 修改交给 react-dom 渲染时的根组件。
// 给根标签包裹一层组件
// export function rootContainer(container) {
// return React.createElement(ThemeProvider, null, container);
// }
页面跳转
声明式
import { Link } from 'umi';
export default () => (
<Link to="/list">Go to list page</Link>
);
命令式
import { history } from 'umi';
function goToListPage() {
history.push('/list');
}
属性获取
export default (props) => (
<Button onClick={()=>props.history.push('/list');}>Go to list page</Button>
);
引入图片
JS 里使用图片
通过 require 引用相对路径的图片。
比如:
export default () => <img src={require('./foo.png')} />
支持别名,比如通过 @ 指向 src 目录:
export default () => <img src={require('@/foo.png')} />
JS 里使用svg
组件式引入
import { ReactComponent as Logo } from './logo.svg'
function Analysis() { return <Logo width={90} height={120} />}
url式引入
import logoSrc from './logo.svg'
function Analysis() { return <img src={logoSrc} alt="logo" />}
CSS 里使用图片
通过相对路径引用。
比如,
.logo {
background: url(./foo.png);
}
CSS 里也支持别名,但需要在前面加 ~ 前缀,
.logo {
background: url(~@/foo.png);
}
注意:
-
这是 webpack 的规则,如果切到其他打包工具,可能会有变化
-
less 中同样适用
图片路径问题
项目中使用图片有两种方式,
-
先把图片传到 cdn,然后在 JS 和 CSS 中使用图片的绝对路径
-
把图片放在项目里,然后在 JS 和 CSS 中通过相对路径的方式使用
前者不会有任何问题;后者,如果在 JS 中引用相对路径的图片时,在发布时会根据 publicPath 引入绝对路径,所以就算没有开启 dynamicImport 时,也需要注意 publicPath 的正确性。
Base64 编译
通过相对路径引入图片的时候,如果图片小于 10K,会被编译为 Base64,否则会被构建为独立的图片文件。
10K 这个阈值可以通过 inlineLimit 配置修改。
本文详细记录了React项目的初始化、配置别名、反向代理、样式管理、请求模块、路由模块、全局状态管理和UI库引入等关键步骤。同时,介绍了使用create-react-app、dva.js、umi.js等工具进行脚手架搭建,并讲解了如何配置eslint和prettier以保持代码规范。
1106

被折叠的 条评论
为什么被折叠?



