React使用踩坑记

3,705 阅读3分钟

记录工作中使用react+ antd-design遇到的各种坑,持续更新。平时写文章恨自己吐不出来东西,这篇文章恰恰相反了,anyway,大家看完之后可以有则改之,无则加勉

Q1 Invalid Hook Call Warning

我在项目中使用的hooks写法,本地开发模式没问题,打包到线上一直报错#321,提示Invalid Hook Call Warning,react官方(reactjs.org/warnings/in…)提示导致可能这个错误的原因如下:

You might have mismatching versions of React and React DOM.

You might be breaking the Rules of Hooks.

You might have more than one copy of React in the same app

逐个排查

1 确定react和react-dom是相同版本,16.10.1,支持hooks语法
2 确定自己的代码没有违背hooks的使用准则
3 项目中引入了不止一个react实例???

很快定位到是第三个原因,那就说明应该是打包的配置文件有问题,因为这个报错在开发模式是不存在的,特别说明一下,我们项目中使用的不是官方脚手架create-react-app,是其他开发人员写的webpack配置,打包的时候先dll预打包,来看一下这个webpack.dll.js这个预打包文件,对webpack配置熟悉的人估计可以定位了

const path = require('path');
const webpack = require('webpack');
const HtmlWebpackPlugin = require('html-webpack-plugin');

/*********loaders***********/

/*********loaders***********/

/*********plugins***********/
const UglifyJsPlugin = require('uglifyjs-webpack-plugin');
var definePlugin = new webpack.DefinePlugin({
    "process.env": {
        NODE_ENV: JSON.stringify("production")
    }
});

var providePlugin = new webpack.ProvidePlugin({
    $: "jquery",
    jquery: "jquery",
    "windows.jQuery": "jquery",
    jQuery: "jquery"
});

const dllPlugin = new webpack.DllPlugin({
    path: path.join(__dirname, 'dll', 'manifest-[name].json'),
    name: '[name]'
});

const htmlWebpackPlugin = new HtmlWebpackPlugin(
    {
        title:"云畜牧创新平台",
        filename: '../template.html',
        template: './template-dll.html',
        favicon:"./favicon.ico",
        hash: true,
        chunks:["jquery","react","echarts","bootstrap","redux"]
    }
);


/*********plugins***********/

module.exports = {
    entry: {
        jquery:["jquery"],
        react:["react","react-dom","react-router-dom"],
        echarts:["echarts"],
        bootstrap:["bootstrap","bootstrap-datepicker"],
        redux:["react-redux",redux","redux-saga","redux-saga/effects"]
    },
    output: {
        path: path.join(__dirname, 'dll'),
        publicPath: './dll/',//访问路径
        filename: '[name].js',
        /**
         * output.library
         * 将会定义为 window.${output.library}
         * 在这次的例子中,将会定义为`window.vendor_library`
         */
        library: '[name]'
    },
    // optimization: {
    //    minimizer: [new UglifyJsPlugin()],
    // },
    plugins: [
        providePlugin,
        dllPlugin,
        htmlWebpackPlugin,
        definePlugin //上面压缩文件会产生警告,这个消除警告
    ],
    mode:'production'
};

看不出来没关系,我直接解密吧,问题出在入口这里,

 entry: {
        jquery:["jquery"],
        react:["react","react-dom","react-router-dom"],
        echarts:["echarts"],
        bootstrap:["bootstrap","bootstrap-datepicker"],
        redux:["react-redux",redux","redux-saga","redux-saga/effects"]
    }

react-redux是依赖react的,放到redux这个入口,打包会产生两个react实例,解决办法很简单,移动到react的入口,再打包就不会出现这个问题了

BTW,这个bug我找了一天,午觉都没睡,不要太坑爹,这就是我不喜欢自己手写webpack配置的原因了,出了问题网上只能自己整,用脚手架就可以在网上找到一堆参考方法,我是个懒人,前端的东西我都学不完了,真的没精力再当webpack配置工程师了

2 表单的自动记忆

一个后台管理的项目,用户管理那里需要新建用户,然后打开新建用户的表单,用户名和密码就被自动填充了登录时候的用户名和密码

现在的问题是不能自动填充 网上一堆说用autocomplete="off"的,其实自己去验证,不论这个属性加到表单form上还是input输入框上,根本不起作用!!!设置autocomplete="new-password"才行, 欢迎戳MDN对此属性的解释

3 实现pdf预览功能

不介绍各种react的pdf插件了,插件总是有各种各样的坑,我最开始用的react-pdf,打开一个10M的pdf,浏览器就提示内存不足了,囧!

还是直接用原生方式实现吧

  1. 后端返回的二进制转为blob
  2. 再利用window.URL.createObjectURL生成blobUrl(注意window.URL.createObjectURL的兼容性,ie10+)
  3. 然后把blobUrl赋值给iframe就行了