Android攻城狮前端遇坑指南

1,084 阅读3分钟

决定一个人命运的不是能力而是选择

1.加快安装

npm config set registry registry.npm.taobao.org

2.写代码过程中webstorm底部一直闪烁,代码也提示不了

File->Invalidate Cahes/Restart -> Invalidate and Restart

3.按钮未点击自动执行点击事件

handlerClick = (questionId)=>{
    console.log('我执行了')
}
<button type="button"
   onClick={
    this.handlerClick(question_id)
  }>补习详情
</button>
handlerClick (questionId){
    console.log('我被点击了')
}
<button type="button"
   onClick={
    this.handlerClick.bind(this,question_id)
  }>补习详情
</button>
第一种和第二种是两种常见的函数定义方法,第一种是箭头函数,第二种是普通函数。推荐用箭头函数
  • 避免普通函数this造成的一系列问题,而箭头函数this指向函数定义的组件
  • 每次刷新组件都会重新执行bind方法,对性能有影响
但是第一种箭头函数确带来了奇怪的问题:按钮未点击handlerClick函数自动执行了,而不传参数的话是不会自动执行的,这是为什么?明明看起来两种写法差不多!在讲这个问题之前我们首先来看一下匿名函数
function (){
    console.log('我执行了')
}
忽略箭头函数的内部细节,我们发现其实箭头函数就是匿名函数。再来看看匿名函数是如何执行的
function (){
    console.log('我执行了')
})()
聪明的你应该发现问题了,第一种箭头函数传参就相当于匿名函数立即执行。讲清楚了为什么会立即执行,看下如何解决
<button type="button"
   onClick={()=>{
       this.handlerClick(question_id)
   }
  }>补习详情
</button>
这有什么区别?第一种箭头函数的写法等价于
onClick=(function(){
    console.log('我执行了') 
})(questionId)

第二种等价于

onClick=function(){
    return function handlerClick(questionId){
        console.log('我执行了') 
    }
}
那么bind为什么不会立即执行?因为bind返回的还是函数

4.ant Design Select组件的坑

<Select defaultValue={0} onChange={this.handleClasses} className="selectClasses">
   {
   allClass.map((value, index) =>
          <Select.Option value={index}>{value.class_name}</Select.Option>
       )
    }
</Select>
开始allClass是空数组,等到网络请求返回allClass才有数据,然后组件会刷新。这时候很奇怪defaultValue没有刷新,莫名其妙的设置不了默认数据。会出现下图所示的情况

下面的写法可以避免这种情况
{
 allClass.length !== 0 ?
   <Select defaultValue={0} onChange={this.handleClasses} className="selectClasses">
    {
      allClass.map((value, index) =>
       <Select.Option value={index}>{value.class_name}</Select.Option>
      )
    }
   </Select> : <div/>
}
这种写法更优雅
{
 allClass.length !== 0 &&
   <Select defaultValue={0} onChange={this.handleClasses} className="selectClasses">
    {
      allClass.map((value, index) =>
       <Select.Option value={index}>{value.class_name}</Select.Option>
      )
    }
   </Select>
}

5.react.setState()之后不能获取更新后的数据

下面获取到的count还是-1
this.state={
    count = -1
};
this.setState({ count: 0 });
console.log(this.state.count);
实际上setState并不会立马执行,它会把状态存到队列中,稍后才会更新state的值,下面的写法可以避免这种情况
this.setState({ count: 0 },
() => console.log(this.state.count))

6.自己搞的简易的react Componet

export default class Component {
    constructor(props = {}) {
        this.props = props;
    }

    setState(state) {
        const oldEl = this.el;
        this.state = state;
        this._renderDOM();
        if (this.onStateChange) this.onStateChange(oldEl, this.el);
    }

    _renderDOM() {
        this.el = this._createDOMFromString(this.render());
        if (this.onClick) {
            this.el.addEventListener('click', this.onClick.bind(this), false)
        }
        ;
        return this.el;
    }

    _createDOMFromString = (domString) => {
        const div = document.createElement('div');
        div.innerHTML = domString;
        return div;
    }
    
    mount = (component, wrapper) => {
        wrapper.appendChild(component._renderDOM());
        component.onStateChange = (oldEl, newEl) => {
            wrapper.insertBefore(newEl, oldEl);
            wrapper.removeChild(oldEl);
        }
    }

    onStateChange(oldEl, newEl) {}

    render() {}

    onClick() {}
}

7.react-router-dom使用

函数方式跳转传参
this.props.history.push({
      pathname: '/detail',
      state: {
        id: 3
     }
)

防止重复跳转死循环

this.props.history.replace('/detail');

goBack返回

this.props.history.goBack();

8.redux使用,redux用于数据共享

index.js注册

import counter from './reducers/index';
import {createStore} from 'redux';

const store = createStore(counter);
const render = () =>
    ReactDOM.render(<App
        value={store.getState()}
        onIncrement={() => store.dispatch({type: 'INCREMENT'})}//action
        onDecrement={() => store.dispatch({type: 'DECREMENT'})}
    />, document.getElementById('root'));
render();
store.subscribe(render);
creare函数

export default (state = 0, action) => {
    switch (action.type) {
        case 'INCREMENT':
            return state + 1;
        case 'DECREMENT':
            return state - 1;
        default:
            return state
    }
}
组件

 const {value, onIncrement, onDecrement} = this.props;
 <p>{value}次数拉拉拉</p>
 <button onClick={onIncrement}>加上</button>
 <button onClick={onDecrement}>减去</button>

9.js精度问题

0.07.toFixed()*100 = 7.00000000000000001%
(0.07*100).toFixed() = 7%

好用的js方法

1.正确返回字符串长度
function length(str) {
  return [...str].length;
}

或者

function countSymbols(string) {
  return Array.from(string).length;
}

2.判断一个字符是单字节还是双字节

function is32(c){
  return c.codePointAt(0) > 0xFFFFFF;
};

3.正则判断金额是否正确

let s = "1512.1";
let patter = /^\d+\.?\d{1,2}$/g.test(s);

4.将数组中布尔值为false的成员转为0

Array.from([1, , 2, , 3], (n) => n || 0)

5.数组去重

[...new Set([1,2,3,4,5,2])]

6.去除重复字符串

[...new Set('ababbc')].join('')