【react框架】一些零碎知识点的记录:proxy的代理配置、根元素、按需打包引入、异步组件、元素插入

代理小服务

当我们在本地跑一个react脚手架项目的时候,webpack的devServer会建立一个本地的服务器将项目跑在这上面,然后还会额外开一个小服务器,专门用来作为本地客户端与远程服务端的代理中间人,如下:

react脚手架服务
本地小代理
远程服务器

如果没有这个本地代理会发生请求的跨域问题:

假设本地前端工程服务器启动地址为http://localhost:3000,当我们去请求一个接口(例如 http://localhost:5000/a) 时,服务端接收请求并返回了相应数据,数据回来的时候也是走5000端口,那么react脚手架服务上的axios就会进行拦截,因为跨域了,我们就获取不到这次返回的数据。

跨域相关知识:【网络基础】小白对同源与跨域的初步认识

如果我们配置了本地小代理,那么这个请求首先会在react脚手架服务上找对应地址/a的资源,找不到会给这个本地小代理,让它帮我们去请求远程服务器。

由于代理服务器和远程服务器对接的都是5000端口,所以他俩不会产生跨域问题,能够正常发送接收数据。

而代理服务器在脚手架服务上,所以对接前端工程服务器的端口也是3000,那么代理接收到的服务器相应数据就能完美的转交给react脚手架服务上了。

由于设置了代理,所以脚手架服务请求的地址需要改为代理的地址,也就是同一个3000端口的地址,那么请求方法的url就从http://localhost:5000/a改为http://localhost:3000/a才能正常的走代理服务器。
如果当前项目地址和请求地址一样,还可以把前面部分省略了直接/a即可。

接下来简单讲下怎么在react中配置与代理有关的proxy配置。

package.json中的proxy配置

例如:

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

就是给代理服务器指定远程请求地址为http://localhost:5000,这种配置方式的缺点就是不能配置多个代理。下面来看看怎么配置多个代理。

setupProxy.js代理配置文件

在src下创建配置文件:src/setupProxy.js,这里面写的是CJS规范代码:

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': ''} //去除请求前缀,保证交给后台服务器的是正常请求地址(必须配置),否者请求过去的就是http://localhost:5000/api1/xxxx 而不是正确的 http://localhost:5000/xxxx
    }),
    proxy('/api2', { 
      target: 'http://localhost:5001',
      changeOrigin: true,
      pathRewrite: {'^/api2': ''}
    })
  )
}
  1. 优点:可以配置多个代理,可以灵活的控制请求是否走代理。
  2. 缺点:配置繁琐,前端请求资源时必须加前缀(可以通过全局变量解决)。

借助craco库拓展webpack配置

具体可以看:

介绍:https://www.lingjie.tech/article/2021-01-04/27
库的官方地址:https://github.com/dilanx/craco
也可以看看这个博客【React项目使用craco(由create-react-app创建项目)


Fragment 根组件

jsx标签必须返回一个根元素,但有时候并不像渲染一个多余的根元素就可以使用这个,原理类似vue的template标签

<Fragment>
  <img />
  <img />
</Fragment>

还能在遍历中绑定key值,但有且仅有一个key属性

<Fragment key={xxxxxx}>
  <img />
  <img />
</Fragment>

如果不需要绑定key还有个超级简写的方法

<>
  <img />
  <img />
</>

按需打包引入

import React, {lazy } from 'react';
const Demo = lazy(()=>import('./demo')) // 这样打包出来的资源文件名称是哈希值
const Demo = lazy(()=>import(/* webpackChunkName: "demo" */ './demo')) // 这样打包出来的资源文件名称就是我们写的命名了

这种方式连css文件都会顺带分开打包


Suspense

不知道和vue3谁借鉴谁的(doge)

import React, { Component, Suspense } from 'react';

// 在模板中
<Suspense fallback={<div>loading...</div>}> // fallback意思是包裹的组件还没有出来的时候,显示什么
  <Zizujian /> // 这种组件通常是按需引入组件或者数据量大加载比较久的
</Suspense>

一般都会封装成一个懒加载组件:

src/components/LazyLoad/index.js:

import React, { Component, lazy, Suspense } from 'react';

export default class Index extends Component {

  constructor(props) {
    super(props);
    this.state = {

    };
  }

  _renderLazy = () => {
    let Lazy;
    const { component, delay, ...other } = this.props; // 接收自定义组件、延迟加载时间,自定义组件上的自定义参数
    if (!component || component.constructor.name !== 'Promise') { // 是否传入组件并且传入的是个组件,不是的话渲染一个出错提示页
      Lazy = lazy(() => import('./error'));
    } else {
      Lazy = lazy(() => {
        return new Promise(resolve => {
          setTimeout(() => {
            resolve(component); // 导出传入的组件
          }, delay || 300);
        })
      });
    }
    
    return <Lazy {...other} />
  }

  render() {
    return (
      <div>
        <Suspense fallback={<div>loading...</div>}>
          {this._renderLazy()}
        </Suspense>
      </div>
    )
  }
}

src/components/LazyLoad/error.js:

import React, { Component } from 'react';

export default class Error extends Component {

  constructor(props) {
    super(props);
    this.state = {

    };
  }

  render() {
    return (
      <div>
        组件引入错误!
      </div>
    )
  }
}

使用:

import LazyLoad from '@/components/LazyLoad'

// 在模板中
<LazyLoad component={import('./lists')} delay={300} name='小明'/>

createPortal

这个就是把react dom插入到一个元素里,常用于构建全局弹窗。附个使用例子:

import React, { Component } from 'react';
import ReactDOM from 'react-dom';

export default class CreatePortal extends Component {

  constructor(props) {
    super(props);
    this.body = document.querySelector('body');
    this.el = document.createElement('div');
  }

  componentDidMount() {
    this.el.setAttribute('id', 'portal-root');
    this.body.appendChild(this.el);
  }

  componentWillUnmount() {
    this.body.removeChild(this.el);
  }

  render() {
    return ReactDOM.createPortal(this.props.children, this.el) // 把react dom插入到创建的元素,然后这个元素又被插入到body元素里
  }
}

然后写全局弹窗的组件就可以引入这个组件:

import React, { Component } from 'react';
import CreatePortal from './CreatePortal';

export default class Modal extends Component {
  constructor(props) {
    super(props);
    this.state = {};
  }

  handleClose = ()=>{ // 点击关闭(暴露)
    const { onClose } = this.props;
    onClose && onClose();
  }

  render() {
    const { show } = this.props;
    return (
      <>
        {show ? <CreatePortal>
          <div>
            {this.props.children}
            <div onClick={this.handleClose}></div>
          </div>
        </CreatePortal> : null}
      </>
    )
  }
}

然后就可以使用了:

import React, { Component } from 'react';
import Modal from '@/components/Modal';
import { Button } from 'antd-mobile'; 

export default class Index extends Component {

  constructor(props) {
    super(props);
    this.state = {
      show: false
    };
  }

  handleClick = ()=>{
    this.setState({
      show: true
    })
  }

  handleClose = ()=>{
    this.setState({
      show: false
    })
  }

  render() {
    return (
      <div>
        <Button type='primary' onClick={this.handleClick}>modal</Button>
        <Modal 
          show={this.state.show}
          onClose={this.handleClose}>modal</Modal>
      </div>
    )
  }
}
  • 3
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值