Learn React

114 阅读5分钟

网络请求-axios

跨域的解决方案

  • 配套依赖:axios/qs/react-cookie/[http-proxy-middleware!]
// 安装依赖
npm i -s http-proxy-middleware/axios 

// 在src目录下新建setupProxy.js文件以便对跨域做配置 ↓配置
const { createProxyMiddleware } = require("http-proxy-middleware");

module.exports = function (app) {
  app.use(
    createProxyMiddleware("/chair", {
      target: "https://xy.cozzia.com.cn",
      changeOrigin: true,
      pathRewrite: {
        "^/chair": "/",
      },
      secure: true, //如果访问的是https类的链接,就需要设置为true
    })
  );
};

// 在需要网络请求的文件下 发起请求。
// 由于后端对请求格式有需要,这里的qs对post的数据做处理(单定义content-type没用哦)
axios.post(`/rechargeBill/refundBill`, qs.stringify(data), {
        headers: {
          "Content-type": "application/x-www-form-urlencoded;charset=utf-8",
        },})

redux

初级使用

// 导入redux
const redux = require("redux");
// 初始化State
const initialState = {
  num: 0,
};
// 创建reducer函数
function reducer(state = initialState, action) {
  switch (action.type) {
    case "add":
      return { ...state, num: state.num + 1 };
    case "sub":
      return { ...state, num: state.num - 12 };

    default:
      return state;
  }
}
// 初始化store-创建需要传入reducer
const store = redux.createStore(reducer);
// 订阅改变
store.subscribe(() => {
  console.log("num", store.getState().num);
});
// 定义action
const action1 = { type: "add" };
const action2 = { type: "sub" };
// 派发action
store.dispatch(action1);
store.dispatch(action2);

入门使用

目录utils-connect.js

import React, { PureComponent } from "react";
// context函数
import { StoreContext } from "./context";

// 高阶函数
function EnhanceConnect(mapStateToProps, mapDispatchToProps) {
  // connect(mapStateToProps, mapDispatchToProps)(Home);
  //                                  ↓接收高阶组建↑  
  return function High(WrapperComponent) {
    class EnhanceComponent extends PureComponent {
      constructor(props,context) {
        super(props,context);
        this.state = {
          // 初始化State,具体要state的什么数据 从mapStateToProps里定义
          storeState: mapStateToProps(context.getState()),
        };
      }

      componentDidMount() {
        this.unsubscribe = this.context.subscribe(() => {
          this.setState({
            storeState: mapStateToProps(this.context.getState()),
          });
        });
      }

      render() {
        return (
          <div>
            <WrapperComponent
               // 把state里的数据通过props传下去给 高阶组件
              {...this.props}
              {...mapStateToProps(this.context.getState())}
              {...mapDispatchToProps(this.context.dispatch)}
            />
          </div>
        );
      }
    }
     // index.js里定义好的store  作用:把store传下去
    EnhanceComponent.contextType = StoreContext;
    return EnhanceComponent;
  };
}

export default EnhanceConnect;

目录page-about.js

import React, { PureComponent } from "react";

// 导入action 同vuex用法差不多
import { addAction, subAction } from "../../store/actionCreater";
// ↑上面提到的组件
import connect from "../../utils/connect";

class Home extends PureComponent {
  constructor(props){
    super(props)
  }
  render() {
    return (
      // 傀儡dom  用this.props接收上方 {...mapStateToProps(this.context.getState())} 传来的值
      <div>
        <h1>Home</h1>
        <span>当前计数:{this.props.num}</span>
        <button onClick={this.props.clickAdd}>+1</button>
      </div>
    );
  }
}

const mapstate = (store) => {
// 向store索要num
  return { num: store.num };
};

const mapdispatch = (dispatch) => {
  return {
    clickAdd() {
      dispatch(addAction(1));
    },
  };
};

const enhanceHome = connect(mapstate, mapdispatch)(Home);

export default enhanceHome;

移动端自适应

rem配置

  • 安装postcss-pxtorem依赖
npm i postcss-pxtorem -s
  • 开启webpack配置文件(若遇到git相关报错,先把更改的文件git push上去再yarn eject)
yarn eject
  • 再webpack.config.js文件下引入postcss-pxtorem
const px2rem = require('postcss-pxtorem')
-----------------------------------------------
postcssOptions: {
            // Necessary for external CSS imports to work
            // https://github.com/facebook/create-react-app/issues/2677
            ident: "postcss",
            config: false,
            plugins: !useTailwind
              ? [
			  // 加上↓  的意思就是1rem = 75px 这个是根据750px设计稿来的
                  px2rem({ rootValue: 75, unitPrecision: 5, propList: ["*"] }),
                  "postcss-flexbugs-fixes",
                  [
                    "postcss-preset-env",
                    {
                      autoprefixer: {
                        flexbox: "no-2009",
                      },
                      stage: 3,
                    },
                  ],

                  // Adds PostCSS Normalize as the reset css with default options,
                  // so that it honors browserslist config in package.json
                  // which in turn let's users customize the target behavior as per their needs.
                  "postcss-normalize",
                ]
// 省略...
  • 再index.js文件引入lib-flexible
import 'lib-flexible'
  • !重要 兼容ios初始滚动条问题 index.html
 <script>
    /(iPhone|iPad|iPhone OS|Phone|iPod|iOS)/i.test(navigator.userAgent) && (head = document.getElementsByTagName('head'), viewport = document.createElement('meta'), viewport.name = 'viewport', viewport.content = 'target-densitydpi=device-dpi, width=480px, user-scalable=no', head.length > 0 && head[head.length - 1].appendChild(viewport));
  </script>
  • over写的px自动转成rem

移动端快速点击

  • 场景:抽奖转盘,快速连点会触发不可预料的后果,用比对时间戳的方法防止快速双击!
if (this.state.BeginTimestamp + 2000 > new Date().getTime()) {
      return false;
    }
    this.state.BeginTimestamp = new Date().getTime();

打包部署问题

静态文件

如果 图片超过webpack配置文件中的限制大小,则不转成base64,直接打进/media文件夹,不被打包。若需要图片被打包,则将webpack限制大小调大

  • 文件:webpack.config.js ;适当调大
const imageInlineSizeLimit = parseInt(
  process.env.IMAGE_INLINE_SIZE_LIMIT || '1000000'
);

homepage指向改为相对路径

  • 场景:一个nginx下代理多个文件夹下的应用,相对路径就会走丢变为:/static。显然这不可能访问到各个文件夹下依赖的静态文件
  • 文件:package.json下新增
"homepage": ".",

Umi的使用(antdPro)

安装

官方:yarn create @umijs/umi-app
// 但是官方的用法实战报错(yarn的锅),遂用↓
npm create @umijs/umi-app

// 加载依赖
yarn

前端国际化(useIntl方法)

  • 粗看:↓引入umi带的useIntl方法;key:'pages.welcome.alertMessage',value:对应组件放在语言配置文件中
import { useIntl } from 'umi’;

useIntl().formatMessage({
            id: 'pages.welcome.alertMessage',
			// 找不到国际化键值对时展示的默认值。
            defaultMessage: '更快更强的重型组件,已经发布。',
          })
  • 语言配置文件 键值对关系
export default {
 'pages.welcome.alertMessage': '更快更强的重型组件,已经发布。',
};

Dva嵌入Umi的使用

model用例

  • model.ts结构
pages
    └─users
           index.tsx *
           model.ts *

import { Effect, ImmerReducer, Reducer, Subscription } from 'umi';

export interface UserModelState {
  name: string;
}

export interface UserModelType {
  namespace: 'users';
  state: UserModelState;
  effects: {
    query: Effect;
  };
  reducers: {
    save: Reducer<UserModelState>;
    // 启用 immer 之后
    // save: ImmerReducer<UserModelState>;
  };
  subscriptions: { setup: Subscription };
}

const UserModel: UserModelType = {
  namespace: 'users',

  state: {
    name: '',
  },

  effects: { // 异步
    *query({ payload }, { call, put }) {},
  },
  reducers: { // 同步
    save(state, action) { // 简化save数据输出
      const data = [
        {
          key: '1',
          name: 'John Brown',
          age: 32,
          address: 'New York No. 1 Lake Park',
          tags: ['nice', 'developer'],
        },
        {
          key: '2',
          name: 'Jim Green',
          age: 42,
          address: 'London No. 1 Lake Park',
          tags: ['loser'],
        },
        {
          key: '3',
          name: 'Joe Black',
          age: 32,
          address: 'Sidney No. 1 Lake Park',
          tags: ['cool', 'teacher'],
        },
      ];
      return data
    },
  },
  // 订阅
  subscriptions: { 
    setup({ dispatch, history }) {
      return history.listen(({ pathname }) => {
        if (pathname === '/users') { // 触发前提条件
          dispatch({
            type: 'save', // 触发effect
          });
        }
      });
    },
  },
};

export default UserModel;

页面mapStateToProps用例

  • index.tsx

import { Table, Tag, Space } from 'antd';
import { connect } from 'umi';

// 记得吧users传入
const index = ({ users }) => {
// 此处省略columns配置  antd自己扒

  return (
    <div className='list-table'>
      <Table columns={columns} dataSource={users} />
    </div>
  );
};

// 收mapState  
const mapStateToProps = ({ users }) => {
  return { users };
};

export default connect(mapStateToProps)(index);

Utils

canvas画布吸颜色

drawImage(image, sx, sy, sw, sh, dx, dy, dw, dh)
  1. sx:图像本身需要裁剪的X轴起点
  2. sy:图像本身需要裁剪的Y轴起点(有了XY就有了一个起点)
  3. sw:图像需要裁剪的宽度
  4. sy:图像需要裁剪的高度 将图像抽象到canvas画布上(图中蓝底图中)
  5. dx:抽象后的摆放x轴起点
  6. dy:抽象后的摆放y轴起点(dx,dy讲白了就摆放位置)
  7. dw,dh:绘制的图像宽高
  • 引用美图↓
getImgColor() {
    let img = new Image();
    let canvas = document.getElementById("canvas");
    let ctx = canvas.getContext("2d");
    img.src =
      "https://wxchart.cozzia.com.cn/chair/image/ioReadImage?imgPath=/ogawa/file/upload/reward_shop/202011/1605513392414.png";
    img.crossOrigin = "anonymous";

    img.onload = function () {
       ctx.drawImage(img, 34,175,104,48,0,0,104,48);
      img.style.display = "none";
      let imgData = ctx.getImageData(0, 0, img.width, img.height).data;
      var red = imgData[0];
      var green = imgData[1];
      var blue = imgData[2];
      var alpha = imgData[3]

      console.log(imgData)
      console.log( 'background-color: rgba(' + red + ', ' + green + ', ' + blue + ', ' + alpha + ');');
    };


  }

Refs使用

class/函数组件混合取子组件ref

//父class
export default class index extends PureComponent {
constructor(props) {
    super(props);
    // 注册refs
    this.scrollWinneref = React.createRef();
  }
render(){
   return               <ScrollWinner ref={this.scrollWinneref} />
  }
}

//子函数组件
const ScrollWinner = forwardRef((props, ref) => {
  // *挂载到ref上
  ref.current = { init };
})

Learn UMI

layout踩坑

layout开启

/.umirc.ts

  layout: {
    name: 'XX资本', // 网站名字
    layout: 'side', // layout 的菜单模式, side: 左侧导航 top: 顶部导航 mix: 混合式导航
    navTheme: 'light', // 左侧导航的主题为 浅色 主题
    logo: 'http://v-project.coderv.cn/youpin/logo.png',
  
  },

右上角头像/名称/logout...

  • 注意:getInitialState是umi中的初始化数据方法,组件总消费+使用方法如下
import { history, useModel } from 'umi';

export default () => { 
const { initialState, loading, refresh, setInitialState } = useModel('@@initialState'); 

// 
setInitialState({avatar})

// 读取初始化数据
return <div>{initialState.userName}</div>; 
};

/src/app.tsx

export async function getInitialState(name,avatar) {
  return {
    // name:'vas', // 默认 layout 导航右上角展示的用户名字段
    avatar,  // 默认 layout 导航右上角展示的用户头像字段

  };
}