• React 项目开发中的常见问题


     

    React 中, 在 Controlled(受控制)的文本框中输入中文 onChange 会触发多次

    Issues

    通过输入法输入中文,日文,不管哪种一种用拼音的、笔划的,只要按下键盘的动作都会触发文本框的 change 事件。 但是 React中的受控组件都通过触发 change 事件后得到的值再去更新组件的value, 这样不停的触发 change,导致 value 一直在更新,组件就一直在 render, 可能会造成组件运行逻辑问题,输入框内出现很多字符,而且中文输入不进去。

    在 DOM events 中另外有 3 个事件可以辅助监听一段文字的输入:

    • compositionstart : 事件触发于一段文字的输入之前;
    • compositionupdate : 事件触发于字符被输入到一段文字的时候;
    • compositionend : 事件触发于一段文字的输入完成。

    我们可以通过这 3 个事件判断当前输入是否完整的输入,再触发 onChange 事件,这样就能解决多次触发 onChange 的问题。 还有一个重要的问题,虽然 onChange 要等一次完整输入后才触发,但是文本框上的显示需要是实时的,所以还要考虑在 state 中维护一个 innerValue 做实时更新,这样就没有问题了。

    另外这 3 个事件在各个浏览器上的兼容性不一样,所以还要考虑兼容性的问题。 具体详细的实现可以参考 form-lib

    Warning: It looks like you’re using a minified copy of the development build of React. When deploying React apps to production, make sure to use the production build which skips development warnings and is faster.

    当 React 升级到 v15.* 以后,可能会见到这个警告,它是意思说你在生产环境中使用的是一个开发环境 minified 的代码。

    那 React 它是怎么办判断你正在访问的是生产环境,而不是开发环境呢? 它是通过 webpack 知道的,因为最终发布生产环境的代码都是通过 webpack 命令打包。如果你是在开发环境,那肯定是用 webpack-dev-server。 在生产环境中不应该包括开发中使用的所有额外代码,所以在 webpack 部署环境中需要添加以下配置:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    module.exports = {
    //...
    plugins:[
    new webpack.DefinePlugin({
    'process.env':{
    'NODE_ENV': JSON.stringify('production')
    }
    }),
    new webpack.optimize.UglifyJsPlugin({
    compress:{
    warnings: true
    }
    })
    ]
    //...
    }

    参考Make your own React production version with webpack

    setState(…): Can only update a mounted or mounting component. This usually means you called setState() on an unmounted component. This is a no-op.

    这个警告是说,在一个已经卸载的组件上调用 setState 是无效的。出现这种情况一般都是异步操作造成的,比如一个异步数据请求,响应后执行 setState 去更新组件,但是如果在异步请求未完成前,路由发生变化,页面当前组件被卸载,这个时候异步请求没有被中止,导致等请求完成后就会执行 setState 试图去更新组件,就会报当前错误。

    解决办法很简单,一般都是在执行 setState 之前判断一下当前组件是否被卸载,如果没有被卸载,才执行 setState。在 ES6 以前可以通过 this.isMounted() 来判断当前组件是否装载,如下:

    1
    2
    3
    if(this.isMounted()) { // This is bad.
    this.setState({...});
    }

    但是在 ES6 以后不能用这种方式,这是一种反模式,参考isMounted is an Antipattern

    可以利用组件的生命周期自己维护一个 isMounted 状态, 在 componentDidMount 中把 isMounted 设置为 true,
    在 componentWillUnmount 再将 isMounted 设置为 false。 通过 isMounted 变量来判断组件是否装载。

    Each child in an array or iterator should have a unique key prop.

    这个警告很明确,在遍历子元素的时候,每一个子元素都应该有一个唯一的 key

    参考官网相关说明 lists and keys

    但是这里需要注意,避免使用数组的 index 来作为属性 key 的值,推荐使用唯一 ID。
    参考 Index as a key is an anti-pattern

    1
    2
    3
    4
    5
    const todoItems = todos.map((todo) =>
    <li key={todo.id}>
    {todo.text}
    </li>
    );

    在 IE 11 控制台报错:Objects are not valid as a React child

    错误的全文: error-decoder

    这问题一般会在开发环境中遇到,在使用 React 15.4 以后,如果使用了 react-hot-loader 则必须在热加载之前加载 babel-polyfill, 在你的 webpack.config.js 中参考如下配置:

    1
    2
    3
    4
    5
    6
    7
    entry: [
    'babel-polyfill',
    'react-hot-loader/patch',
    'webpack-dev-server/client?http://127.0.0.1:3000',
    'webpack/hot/only-dev-server',
    path.resolve(__dirname, './scr/index')
    ]

    在 IE 11 控制台报错:Minified exception occurred; use the non-minified dev environment for the full error message and additional helpful warnings.

    如果出现这个错误是提示,在本地环境配置 NODE_ENV=development ,再看一下控制台是否输出了一些更详细的错误信息,参考 Introducing React’s Error Code System 。

    如果这个错误只在 IE 11 浏览器环境出现,一般都是 ES6+ 的语法在IE存在兼容问题,一个比较通用的解决办法就是在项目中引入一个 babel-polyfill

    1
    npm i —save babel-polyfill

    在项目入口,引入 babel-polyfill

    1
    import 'babel-polyfill'

    在 webpack 构建的时候会兼容性处理

    在 IE 11 控制台报错: Promise is undefined

    IE 11 不支持 Promise 对象,解决办法

    1
    npm i —save es6-promise

    在项目入口,引入es6-promise

    1
    import 'es6-promise/auto';

    在 IE 11 浏览器上 FontIcon 图标不显示

    这个问题和 React 没有关系,但是这里也记录一下。
    在 IE11 会下载 .ttf/.woff 字体文件, 通过 Network 我们可以看到字体文件 response headers 中有一个 Pragma:no-cache,由于 IE 似乎有缓存和字体的问题,所有导致图标不能正常显示。所以删除 WEB 服务(Nginx..)中的 Pragma:no-cache 和 Cache-Control:no-store 就能正常访问。

    参考 IE and Cache-Control

    在 React 中使用 debounce

    如果需要在 React 组件中使用 debounce 方法可以参考下面代码

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    class SearchBox extends React.Component {
    constructor(props) {
    super(props);
    this.method = debounce(this.method,300);
    }
    method() {
    //...
    }
    render(){
    return(
    <input onKeyUp={e => {
    e.persist();
    this.handleKeyDown(e);
    }}/>
    )
    }
    }

    因为 React 中 SyntheticEvent 是共用的,也就是说 SyntheticEvent对象将会循环使用。而每次执行完事件后,它所有的属性都将会失效(所有属性的值都被置为了 null)。所以在调用 debounce 方法前,一定要先调用 e.persist()来移除 SyntheticEvent ,并允许 event对象被保留下来以用于你自己的代码。
    参考文章:

  • 相关阅读:
    create-react-app搭建的项目中添加bootstrap
    用es6的Array.reduce()方法计算一个字符串中每个字符出现的次数
    为Docker配置阿里加速器,系统为Debian8
    基于Spring Boot,使用JPA动态调用Sql查询数据
    基于Spring Boot,使用JPA调用Sql Server数据库的存储过程并返回记录集合
    基于Spring Boot,使用JPA操作Sql Server数据库完成CRUD
    ES6,Array.includes()函数的用法
    【编程风格】c++命名约定
    【转】吴恩达的视频课程做成了文字版 ~~~
    【专业学习】常用的技术网站
  • 原文地址:https://www.cnblogs.com/qweeewy/p/10199410.html
Copyright © 2020-2023  润新知