个人react笔记

本文详细记录了React项目的初始化、配置别名、反向代理、样式管理、请求模块、路由模块、全局状态管理和UI库引入等关键步骤。同时,介绍了使用create-react-app、dva.js、umi.js等工具进行脚手架搭建,并讲解了如何配置eslint和prettier以保持代码规范。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一、初始化项目(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);
}

注意:

  1. 这是 webpack 的规则,如果切到其他打包工具,可能会有变化

  2. less 中同样适用

图片路径问题

项目中使用图片有两种方式,

  1. 先把图片传到 cdn,然后在 JS 和 CSS 中使用图片的绝对路径

  2. 把图片放在项目里,然后在 JS 和 CSS 中通过相对路径的方式使用

前者不会有任何问题;后者,如果在 JS 中引用相对路径的图片时,在发布时会根据 publicPath 引入绝对路径,所以就算没有开启 dynamicImport 时,也需要注意 publicPath 的正确性。

Base64 编译

通过相对路径引入图片的时候,如果图片小于 10K,会被编译为 Base64,否则会被构建为独立的图片文件。

10K 这个阈值可以通过 inlineLimit 配置修改。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值