• react脚手架日常学习记录


    一、 初始化React脚手架

    1、基础相关

    react提供的脚手架库:create-react-app
    项目整体技术架构:react + webpack + es6 + eslint
    脚手架开发项目特点:模块化, 组件化, 工程化

    2、创建项目

    (1)全局安装:

         npm i -g create-react-app
    
    • 1

    (2)切换到需要创建项目的目录后,创建项目文件夹:

         create-react-app hello-react
    
    • 1

    (3)进入项目文件夹:

       cd hello-react
    
    • 1

    (4)启动项目:

       npm start
    
    • 1
    3、脚手架项目结构
    public ---- 静态资源文件夹
    	favicon.icon ------ 网站页签图标
    	index.html -------- 主页面
    	logo192.png ------- logo图
    	logo512.png ------- logo图
    	manifest.json ----- 应用加壳的配置文件
    	robots.txt -------- 爬虫协议文件
    src ---- 源码文件夹
    	App.css -------- App组件的样式
    	App.js --------- App组件
    	App.test.js ---- 用于给App做测试
    	index.css ------ 样式
    	index.js ------- 入口文件
    	logo.svg ------- logo图
    	reportWebVitals.js
    		--- 页面性能分析文件(需要web-vitals库的支持)
    	setupTests.js
    		---- 组件单元测试的文件(需要jest-dom库的支持)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    4、流程相关

    1、react通过index.js(入口文件),引入react及react-dom/client库,引入页面组件APP.js,通过ReactDOM.render渲染组件到页面(根组件root,即index.html文件中页面元素)
    在这里插入图片描述

    2、App.js文件中,通过es6中的export default默认导出函数类组件APP
    细节:注意类名用className,而不是class

    3、APP外侧包裹React.StrictMode,可以帮忙检查代码不合理的地方
    4、index.html文件中,%PUBLIC_URL%代表public这个文件夹的路径

    二、 规范相关

    1、命名注意事项
    (1)、文件夹名字用大写开头
    (2)、区分是否是组件js文件还是函数方法js文件:

      a. 组件用jsx结尾
      b. 组件js文件用大写开头,函数方法js文件用小写开头
    
    • 1
    • 2

    2、样式跟其它组件冲突的解决办法

     1、css的情况下:样式名称+module命名,接收时import hello from './index.module.css',使用{hello.title}接收时import
    2、使用less,用嵌套即可
    	.box{
       			.title{
       		 }
    	}
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    3、生成代码快捷片段
    安装ES7+ React/Redux/React-Native snippets插件后

      rcc:生成类式组件  --react class component
     rfc:生成函数式组件  --react function component
    
    • 1
    • 2

    三、 input相关

    1、判断input是否是回车按键

    event.keyCode === 13
    
    • 1

    2、input框类型为checkbox时,获取是否选中值

    event.target.checked
    
    • 1

    3、input框类型为text时,获取输入值

    event.target.value
    
    • 1

    4、input框鼠标移入移出事件

    鼠标移入:onMouseEnter
    鼠标移出:onMouseLeave
    
    • 1
    • 2

    四、 react父子组件传值

    1、父传子
    父组件在绑定的子组件上直接传属性值,注意尽量用{…obj}的形式
    在这里插入图片描述
    子组件用解构赋值取props中对应的值即可
    在这里插入图片描述
    2、子传父
    父组件在绑定的子组件绑定的属性上传的为函数
    在这里插入图片描述
    子组件通过this.props.addTodo(todoObj)给父组件传值,addTodo为父组件中在子组件上绑定的属性名
    在这里插入图片描述

    五、 TodoList案例小总结

    1、拆分组件、实现静态组件,注意:className,style的写法
    2、动态初始化列表,如何确定将数据放在哪个组件的state中?
        --某个组件使用:放在自身的state中
        --某些组件使用:放在他们共同的父组件state中(官方称此操作为:状态提升)
    3、关于父子组件通信:
        1. 【父组件】给【子组件】传递数据:通过props传递
        2. 【子组件】给【父组件】传递数据:通过props传递,要求父组件提前给子组件传递一个函数
    4、注意 defaultChecked 和 checked 的区别,类似的还有 defaultValue 和 value
    5、状态在哪里,操作状态的方法就在哪里
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    六、 reduce方法复习

    array.reduce(function(accumulator, currentValue, currentIndex, array), initialValue)
    
    • 1

    reduce用法

    八、 react脚手架配置代理

    1、配置单个代理

    在package.json中追加如下配置

    "proxy":"http://localhost:5000"
    
    • 1

    说明:

    1. 优点:配置简单,前端请求资源时可以不加任何前缀。
    2. 缺点:不能配置多个代理。
    3. 工作方式:上述方式配置代理,当请求了3000不存在的资源时,那么该请求会转发给5000 (优先匹配前端资源)

    2、配置多个代理

    1. 第一步:创建代理配置文件

      在src下创建配置文件:src/setupProxy.js
      
      • 1
    2. 编写setupProxy.js配置具体代理规则:

      const proxy = require('http-proxy-middleware')
      
      module.exports = function(app) {
        app.use(
          proxy('/api1', {  //api1是需要转发的请求(所有带有/api1前缀的请求都会转发给5000)
            target: 'http://localhost:5000', //配置转发目标地址(能返回数据的服务器地址)
            changeOrigin: true, //控制服务器接收到的请求头中host字段的值
            /*
            	changeOrigin设置为true时,服务器收到的请求头中的host为:localhost:5000
            	changeOrigin设置为false时,服务器收到的请求头中的host为:localhost:3000
            	changeOrigin默认值为false,但我们一般将changeOrigin值设为true
            */
            pathRewrite: {'^/api1': ''} //去除请求前缀,保证交给后台服务器的是正常请求地址(必须配置)
          }),
          proxy('/api2', { 
            target: 'http://localhost:5001',
            changeOrigin: true,
            pathRewrite: {'^/api2': ''}
          })
        )
      }
      
      • 1
      • 2
      • 3
      • 4
      • 5
      • 6
      • 7
      • 8
      • 9
      • 10
      • 11
      • 12
      • 13
      • 14
      • 15
      • 16
      • 17
      • 18
      • 19
      • 20
      • 21

    说明:

    1. 优点:可以配置多个代理,可以灵活的控制请求是否走代理。
    2. 缺点:配置繁琐,前端请求资源时必须加前缀。

    3、react配置完setupProxy.js然后运行项目无法访问

    可能会因为版本出现此问题,解决办法为从http-proxy-middleware单个引入createProxyMiddleware

    const { createProxyMiddleware } = require("http-proxy-middleware");
    // const proxy = require("http-proxy-middleware");
     
    module.exports = function (app) {
      app.use(
        createProxyMiddleware("/api1", {
          target: "http://192.168.1.13:5000",
          changeOrigin: true,
          pathRewrite: { "^/api1": "" },
        })
      );
    };
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    九、 消息订阅-发布机制

    工具库:PubSubJS
    作用:可用于组件间传值

    1、下载

    npm install pubsub-js --save

    2、使用

    1)	import PubSub from 'pubsub-js' //引入
    2)	PubSub.subscribe('delete', function(data){ }); //订阅
    3)	PubSub.publish('delete', data) //发布消息
    4) PubSub.unsubscribe(token) //组件销毁时取消订阅消息
    
    • 1
    • 2
    • 3
    • 4

    例如:兄弟组件传值(Search组件向List组件传值)
    在这里插入图片描述
    在这里插入图片描述
    注意:一般在组件销毁时需要取消订阅
    在这里插入图片描述

    十、 Fetch

    注意:fetch方法返回的为promise对象,且需要用try…catch处理异常情况
    特点:etch: 原生函数,不再使用XmlHttpRequest对象提交ajax请求;但兼容性较差,老版浏览器可能不支持

    try {
        const response = await fetch(`/api1/search/users2?q=${keyWord}`)
        const data = await response.json()
        PubSub.publish('atguigu', {isLoading: false,  users: data.items})
    } catch (error) {
        PubSub.publish('atguigu', {isLoading: false, err: error.message})
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    相关文档:
    fetch官方文档
    传统Ajax已死,Fetch永生

    十一、 React路由

    1、SPA的理解

    单页Web应用(single page web application,SPA)。
    整个应用只有一个完整的页面。
    点击页面中的链接不会刷新页面,只会做页面的局部更新。
    数据都需要通过ajax请求获取, 并在前端异步展现。
    
    • 1
    • 2
    • 3
    • 4

    5.24总结(视频P77-P86)

    2、路由的基本使用

    2.1、下载react-router-dom:
    npm install --save react-router-dom
    
    • 1
    2.2、组件引入
    import { Link, Route } from 'react-router-dom'
    
    • 1
    2.3、使用

    1)、在index.html中,引入BrowserRouter,且App外层包裹路由

    import {BrowserRouter} from 'react-router-dom'
    // import {HashRouter} from 'react-router-dom'
    
    const root = ReactDOM.createRoot(document.getElementById('root'))
    root.render(
        <BrowserRouter>
            <App/>
        </BrowserRouter>
        
    )
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    2)、编写路由链接 – 在React中靠路由链接实现切换组件

    <Link className="list-group-item" to='/about'>About</Link>
    
    • 1

    3)、注册路由

    <Route path='/about' component={About}/>
    
    • 1

    3、路由的相关API

    3.1、Link

    作用: 导航不需要高亮显示
    属性:
    to:跳转路径
    标签体为特殊的属性children

    <Link to='/about'>About</Link>
    
    • 1
    3.2、Route

    作用: 注册路由,默认为模糊匹配
    属性:
    path:组件跳转匹配的路径
    component:跳转路径对应的组件
    exact:true 开启严格匹配模式(一般不用,会导致二级路由出现问题)

    <Route path='/about' component={About}/>
    <Route exact path='/about' component={About}/>// 开启严格匹配模式
    
    • 1
    • 2
    3.3、NavLink

    作用: 导航需要高亮显示,会默认高亮加上active样式,可以通过activeClassName自定义高亮央视
    属性:
    to:跳转路径
    activeClassName:自定义高亮样式
    标签体为特殊的属性children

    <NavLink activeClassName='atguigu' to='/about'>About</NavLink>
    
    • 1
    3.4、Switch

    作用: 当一个路径对应两个组件时,会都显示,外层加上Switch可以使路由只显示相同路径下的第一个组件

    <Switch>
        <Route path='/home' component={Home}/>
        <Route path='/home' component={Test}/>
    </Switch>
    
    • 1
    • 2
    • 3
    • 4
    3.5、Redirect

    作用: 当找不到对应组件时,默认跳转组件路径
    属性:
    to:组件跳转路径

    <Redirect to='/about' />
    
    • 1

    4、嵌套路由

    二级路由要添加上一级路由的路径

    // news的上一级路由为home,前面必须加上/home
    <NavLink to='/home/news'>News</NavLink>
    <Route path='/home/news' component={News} />
    
    • 1
    • 2
    • 3

    5、向路由组件传递参数数据

    5.1、params参数

    1) 向路由组件传递params参数

    <Link to={'/home/message/detail/tom/18'}>标签体内容</Link>
    
    • 1

    2) 声明接收params参数

    <Route path='/home/message/detail/:name/:age' component={Detail}></Route>
    
    • 1

    3) 路由组件接收参数(this.props.match.params)

    const {name, age} = this.props.match.params
    
    • 1
    5.2、search参数

    1) 向路由组件传递search参数

    <Link to={'/home/message/detail/?name=tom&age=18'}>标签体内容</Link>
    
    • 1

    2)search参数无需声明接收,正常注册路由即可

    <Route path='/home/message/detail' component={Detail}></Route>
    
    • 1

    3) 路由组件接收参数

    需要借助qs将拿到的字符串参数改为对象

    import qs from 'qs'  //安装依赖为npm install qs --save
    
    const {search} = this.props.location
    const {name, age} = qs.parse(search.substring(1)) // 截掉问号
    
    • 1
    • 2
    • 3
    • 4
    5.3、state参数

    1) 向路由组件传递state参数

    <Link to={{pathname:'/home/message/detail', state:{name:'tom', age: 18}}}>标签体内容</Link>
    
    • 1

    2)state参数无需声明接收,正常注册路由即可

    <Route path='/home/message/detail' component={Detail}></Route>
    
    • 1

    3) 路由组件接收参数

    const {name, age} = this.props.location.state || {}
    
    • 1

    6、编程式路由导航

    借助this.prosp.history对象上的API对操作路由跳转、前进、后退

    this.prosp.history.push()
    this.prosp.history.replace()
    this.prosp.history.goBack()
    this.prosp.history.goForward()
    this.prosp.history.go()
    
    • 1
    • 2
    • 3
    • 4
    • 5
    replaceShow = (id,title) => {
        // replace跳转+携带params参数
        // this.props.history.replace(`/home/message/detail/${id}/${title}`)
    
        // replace跳转 + 携带query参数
        // this.props.history.replace(`/home/message/detail?id=${id}&title=${title}`)
        
        // replace跳转 + 携带state参数
        this.props.history.replace('/home/message/detail', {id:id, title: title})
    }
    
    pushShow = (id, title) => {
        // push跳转+携带params参数
        // this.props.history.push(`/home/message/detail/${id}/${title}`)
    
        // push跳转+携带query参数
        // this.props.history.push(`/home/message/detail?id=${id}&title=${title}`)
    
        // push跳转+携带state参数
        this.props.history.push('/home/message/detail', {id:id, title: title})
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21

    7、BrowserRouter与HashRouter的区别

    1.底层原理不一样:
    		BrowserRouter使用的是H5的history API,不兼容IE9及以下版本。
    		HashRouter使用的是URL的哈希值。
    2.path表现形式不一样
    		BrowserRouter的路径中没有#,例如:localhost:3000/demo/test
    		HashRouter的路径包含#,例如:localhost:3000/#/demo/test
    3.刷新后对路由state参数的影响
    		(1).BrowserRouter没有任何影响,因为state保存在history对象中。
    		(2).HashRouter刷新后会导致路由state参数的丢失!!!
    4.备注:HashRouter可以用于解决一些路径错误相关的问题。
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    8、其它

    6.1、封装NavLink

    作用:多个Link有一样样式时,会导致代码冗余,如以下情况
    在这里插入图片描述

    import React, { Component } from 'react'
    import { NavLink } from 'react-router-dom'
    
    export default class MyNavLink extends Component {
        render() {
            // 标签体内容通过this.props.children接收
            return (
                <NavLink activeClassName='atguigu' className="list-group-item" {...this.props}/>
            )
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    6.2、解决样式丢失问题

    index.html文件中,若通过./的方式引入css文件,可能会导致样式丢失
    解决办法:
    1)、去掉.(推荐)

    <link rel="stylesheet" href="/css/bootstrap.css">
    
    • 1

    2)、使用%PUBLIC_URL%(推荐)

     <link rel="stylesheet" href="%PUBLIC_URL%/css/bootstrap.css">
    
    • 1

    3)、使用HashRouter包裹App(不推荐)

    import {HashRouter} from 'react-router-dom'
    <HashRouter>
        <App/>
    </HashRouter>
    
    • 1
    • 2
    • 3
    • 4
    6.3、qs的用法

    安装: npm install qs --save
    引入:import qs from 'qs'
    使用:

    let obj = {name:'tom', age:18}  // key=value&key=value  urlencoden编码形式字符串
    console.log(qs.stringify(obj))  //name=tom&age=18
    
    let str = "carName='奔驰'&price=99"
    console.log(qs.parse(str))  // {carName: '奔驰', price: 99} 
    
    • 1
    • 2
    • 3
    • 4
    • 5

    补充:key=value&key=value 这种格式称之为urlencoden编码字符串

    九、antd的按需引入+自定主题

    1.安装依赖:

    yarn add react-app-rewired customize-cra babel-plugin-import less less-loader
    
    • 1

    2.修改package.json

    "scripts": {
    	"start": "react-app-rewired start",
    	"build": "react-app-rewired build",
    	"test": "react-app-rewired test",
    	"eject": "react-scripts eject"
    },
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    3.根目录下创建config-overrides.js

    //配置具体的修改规则
    const { override, fixBabelImports,addLessLoader} = require('customize-cra');
    module.exports = override(
    	fixBabelImports('import', {
    		libraryName: 'antd',
    		libraryDirectory: 'es',
    		style: true,
    	}),
    	addLessLoader({
    		lessOptions:{
    			javascriptEnabled: true,
    			modifyVars: { '@primary-color': 'green' },
    		}
    	}),
    );
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    4.备注:
    1)、不用在组件里亲自引入样式了,即:import 'antd/dist/antd.css’应该删掉
    2)、若上述写法报错,则根据官方文档改为最新的按需引入方式即可(或者降低less-loader版本)

    官方文档:antd按需引入样式+自定义主题官方文档

  • 相关阅读:
    Springboot整合rabbitMQ
    哈工大李治军老师操作系统笔记【12】:CPU调度策略(Learning OS Concepts By Coding Them !)
    使用PyTorch解决多分类问题:构建、训练和评估深度学习模型
    Openmldb 踩坑0.53
    【CSS】CSS选择器汇总
    企业架构LNMP学习笔记61
    SpringBoot 使用WebSocket打造在线聊天室
    线程概念,实现方式以及多线程模型
    【数据结构】【版本1.3】【线性时代】——栈
    超级圣诞树(BC115) 【题解】超详细
  • 原文地址:https://blog.csdn.net/weixin_42582488/article/details/124936258