react脚手架日常学习记录

一、 初始化React脚手架

1、基础相关

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

2、创建项目

(1)全局安装:

     npm i -g create-react-app

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

     create-react-app hello-react

(3)进入项目文件夹:

   cd hello-react

(4)启动项目:

   npm start
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库的支持)

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文件用小写开头

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

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

.box{
   .title{
   }
}

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

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

三、 input相关

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

event.keyCode === 13

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

event.target.checked

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

event.target.value

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

鼠标移入:onMouseEnter
鼠标移出:onMouseLeave

四、 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、状态在哪里,操作状态的方法就在哪里

六、 reduce方法复习

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

reduce用法

八、 react脚手架配置代理

1、配置单个代理

在package.json中追加如下配置

"proxy":"http://localhost:5000"

说明:

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

    在src下创建配置文件:src/setupProxy.js
    
  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、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": "" },
    })
  );
};

九、 消息订阅-发布机制

工具库: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) //组件销毁时取消订阅消息
     例如:兄弟组件传值(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})
}

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

十一、 React路由

1、SPA的理解

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

2、路由的基本使用
2.1、下载react-router-dom:
npm install --save react-router-dom
2.2、组件引入
import { Link, Route } from 'react-router-dom'
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>
    
)

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

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

3)、注册路由

<Route path='/about' component={About}/>
3、路由的相关API
3.1、Link

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

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

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

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

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

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

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

<Switch>
    <Route path='/home' component={Home}/>
    <Route path='/home' component={Test}/>
</Switch>
3.5、Redirect

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

<Redirect to='/about' />
4、嵌套路由

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

// news的上一级路由为home,前面必须加上/home
<NavLink to='/home/news'>News</NavLink>
<Route path='/home/news' component={News} />
5、向路由组件传递参数数据
5.1、params参数

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

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

2) 声明接收params参数

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

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

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

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

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

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

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

3) 路由组件接收参数

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

import qs from 'qs'  //安装依赖为npm install qs --save

const {search} = this.props.location
const {name, age} = qs.parse(search.substring(1)) // 截掉问号
5.3、state参数

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

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

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

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

3) 路由组件接收参数

const {name, age} = this.props.location.state || {}
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()

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})
}
7、lazyLoad
//1.通过React的lazy函数配合import()函数动态加载路由组件 ===> 路由组件代码会被分开打包
const Login = lazy(()=>import('@/pages/Login'))
	
//2.通过<Suspense>指定在加载得到路由打包文件前显示一个自定义loading界面
<Suspense fallback={<h1>loading.....</h1>}>
    <Switch>
        <Route path="/xxx" component={Xxxx}/>
        <Redirect to="/login"/>
    </Switch>
</Suspense>
8、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可以用于解决一些路径错误相关的问题。

8、其它
6.1、Fragment

加上后可以不用必须有一个真实的DOM根标签了,类似于vue中的telement

<Fragment><Fragment>
<></>
6.2、Context

一种组件间通信方式, 常用于【祖组件】与【后代组件】间通信
1、创建Context容器对象

const XxxContext = React.createContext()  

2、渲染子组时,外面包裹xxxContext.Provider, 通过value属性给后代组件传递数据

<xxxContext.Provider value={数据}>
	子组件
</xxxContext.Provider>

在应用开发中一般不用context, 一般都用它的封装react插件
3、后代组件读取数据

//第一种方式:仅适用于类组件 
  static contextType = xxxContext  // 声明接收context
  this.context // 读取context中的value数据
  
//第二种方式: 函数组件与类组件都可以
  <xxxContext.Consumer>
    {
      value => ( // value就是context中的value数据
        要显示的内容
      )
    }
  </xxxContext.Consumer>
6.3、组件优化

优化点:
1、只要执行setState(),即使不改变状态数据, 组件也会重新render() ==> 效率低
2、只当前组件重新render(), 就会自动重新render子组件,纵使子组件没有用到父组件的任何数据
解决:使用PureComponent,PureComponent重写了shouldComponentUpdate(), 只有state或props数据有变化才返回true

import React, { PureComponent } from 'react'
export default class Parent extends PureComponent {}
6.4、render props

类似于vue中slot
1、children props(组件间无法传递数据)

<A>
	 <B>xxxx</B>
</A>
{this.props.children}

2、render props

<A render={(data) => <C data={data}></C>}></A>
A组件: {this.props.render(内部state数据)}
C组件: 读取A组件传入的数据显示 {this.props.data} 
6.5、错误边界

错误边界(Error boundary):用来捕获后代组件错误,渲染出备用页面(只能捕获后代组件生命周期产生的错误)
使用:getDerivedStateFromError配合componentDidCatch

// 生命周期函数,一旦后台组件报错,就会触发
static getDerivedStateFromError(error) {
    console.log(error);
    // 在render之前触发
    // 返回新的state
    return {
        hasError: true,
    };
}

componentDidCatch(error, info) {
    // 统计页面的错误。发送请求发送到后台去
    console.log(error, info);
}
6.6、封装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}/>
        )
    }
}
6.7、解决样式丢失问题

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

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

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

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

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

import {HashRouter} from 'react-router-dom'
<HashRouter>
    <App/>
</HashRouter>
6.8、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} 

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

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

1.安装依赖:

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

2.修改package.json

"scripts": {
	"start": "react-app-rewired start",
	"build": "react-app-rewired build",
	"test": "react-app-rewired test",
	"eject": "react-scripts eject"
},

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' },
		}
	}),
);

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

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

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值