阅读 115

React基础知识以及一些踩坑的点

  1. React组件采用ES6 class的写法:
import React, {Component} from 'react';
class Children extends Component{
    constructor(props){
        super(props); //调用父类的构造函数,固定写法,继承父组件属性
        this.state = {
            value:'',
            list:[]
        }
    }
   render(){
       return ();
   }
}
复制代码
  1. 标签添加样式类名,不能用''class",要用"className"
  2. 利用props继承父组件的属性(单向数据流);
  3. 利用state声明响应式变量;
  4. React事件的钩子命名采用小驼峰写法:onClick 、 onChange等;
  5. 要在constructor函数里面为事件绑定this,写法:
this.inputChange=this.inputChange.bind(this);
复制代码

这种在组件里面可以直接使用:

onChange={this.inputChange};
复制代码

如果不使用这种方式,则可以在声明函数时采用“箭头函数”的写法:

inputChange = (e) =>{
    this.setState({
        inputValue : e.target.value
    })
}
复制代码
  1. 利用循环生成节点时,要记得为item设置'key':
  <ul>
       {
            this.state.list.map((item,index) =>{
                return <li 
                key={index+item}
                onClick={this.deleteItem.bind(this,index)}
                >
                {item}
                </li>
            })
       }
 </ul> 
复制代码
  1. 在React里面不允许直接操作state.例如要删除state里面一个数组的某一项,应该先拷贝一份要操作的那个数组,然后对拷贝的数组进行操作,操作完成之后,将state里面那个数组更新为操作之后的数组:
let list = this.state.list; //先拷贝一份
        list.splice(index,1); //对拷贝这个数组进行操作
        this.setState({
            list:list  //操作之后更新
})
复制代码

也就是说不能像这样:

this.state.list.splice(index,1) //直接操作state
   this.setState({
       list:this.state.list
}) 
复制代码
  1. JSX写注释的方法:
 {/*  这是注释 */}
复制代码
  1. React 通过preventDefault()来阻止默认行为:
function handleClick(e) {
    e.preventDefault();
    console.log('The link was clicked.');
}
复制代码
  1. label使用'for'属性,实现点击label即可启用输入框的光标,在React里面for要设置为'htmlFor':
<div>
    <label htmlFor="haha">增加选项:</label>
    <input id="haha" className="input" value={this.state.inputValue} onChange={this.inputChange.bind(this)} />
    <button onClick={this.addList.bind(this)}> 确定 </button>
</div>
复制代码
  1. React父组件向子组件传值:属性名 = {变量}
<Children content={item}></Children>
复制代码

在子组件中使用:

<div>{this.props.content}}</div>
复制代码
  1. 子组件调用父组件的方法,将父组件的方法作为参数传递过去:
<XuanXiangKaItem 
   key={index+item} 
   content={item} 
   index={index}  
   deleteItem = {this.deleteItem.bind(this)}
/>
复制代码

子组件调用:

handleDelete(){
       console.log(this.props.index);
       this.props.deleteItem(this.props.index);
}
复制代码
  1. 在子组件里面,不能直接去修改props传递过来的值,因为react是单向数据流。如果要在子组件里面更改父组件的值,应当将父组件里面的方法通过props一起传递到子组件,然后在子组件里面调用父组件传递过来的方法。
  2. 子组件里面校验父组件传递过来的值,使用PropTypes进行校验:
import PropTypes from 'prop-types';
XuanXiangkaItem.propTypes= {  //写在class之后
    content:PropTypes.string.isRequired //isRequired表示这个参数必须传
    index:PropTypes.number,
    deleteItem:PropTypes.func
}
复制代码
  1. 指定props参数的默认值,使用defaultProps:
XuanXiangkaItem.defaultProps = {
    content:'默认值'
}
复制代码

17.ref的基本使用: //在组件里面

ref={(input)=>(this.input = input)}  //利用箭头函数来绑定

 在函数操作中使用:
 this.setState({
            // inputValue : e.target.value
            inputValue : this.input.value   //取代e.target.value
})
复制代码
  1. ref和setState一起使用的一个坑:
    <ul ref={(ul) => (this.ul = ul)}>
                   {
                        this.state.list.map((item,index) =>{
                            return (
                               <XuanXiangKaItem 
                               key={index+item} 
                               content={item} 
                               index={index}  
                               deleteItem = {this.deleteItem.bind(this)}
                               />
                            )
                        })
                   }
</ul> 
复制代码

在调用setState之后打印ul数组的长度:

 addItem = ()=>{
        this.setState({
            list:[...this.state.list,this.state.inputValue],
            inputValue:''
        })
        console.log(console.log(this.ul.querySelectorAll('div').length)); // 在这里调用
}
复制代码

打印结果会少一个,因为setState是异步的,我们虚拟Dom还没更新就去调用console.log了。 解决方法,利用setState的回调函数:

addItem = ()=>{
        this.setState({
            list:[...this.state.list,this.state.inputValue],
            inputValue:''
        },()=>{ //这里调用setState的回调
            console.log(this.ul.querySelectorAll('div').length);
        }) 
}
复制代码

适用场景:我们在进行了一些数据更新之后,我们想要立即拿到变化之后的虚拟Dom,我们就应当用setState的回调函数。 19. React的生命周期主要分为四大阶段:

Initialization:初始化阶段。
Mounting: 挂载阶段。
Updation: 更新阶段。
Unmounting: 销毁阶段
复制代码

QQ20191106-101739@2x.png

可以看出,render函数是一个生命周期函数,当props、state变化时,都会自动进行调用.

constructor不能称为是生命周期函数,他仅仅是ES6的语法,虽然它和生命周期函数的性质一样,但不能认为是生命周期函数。应该把它看成是React的Initialization阶段,定义属性(props)和状态(state)。

Mounting: 挂载阶段
Mounting阶段,即是挂载阶段,伴随着整个虚拟Dom的生成,这个周期里面有三个生命周期函数:

  1. componentWillMount:在组件即将被挂载到页面的时刻执行,
  2. render:页面props和state发生变化时执行,
  3. componentDidMount:组件挂载(插入dom树中)完成之后执行。

需要注意的问题:componentWillMount和componentDidMount,这两个周期函数,只会在页面刷新时执行一次,但是render则不同,只要页面props和state发生变化时就会执行。所以我们可以将异步请求写在componentWillMount和componentDidMount钩子函数里面,但是在使用RN时,使用componentWillMount钩子会有冲突。所以建议在componentDidMount函数里作异步请求。

Updation: 更新阶段
Updation阶段主要是更新阶段,有两个部分组成,一个是props属性的改变,另一个是state状态的改变。

  1. shouldComponentUpdate:它要求返回一个布尔类型的结果,必须有返回值,简单点说,就是返回true,就同意组件更新;返回false,就反对组件更新,
  2. componentWillUpdate:在组件更新之前,但shouldComponenUpdate之后被执行。但是如果shouldComponentUpdate返回false,这个函数就不会被执行了,
  3. componentDidUpdate:组件更新完成之后执行。

Unmounting: 销毁阶段
Unmounting是指组件的销毁阶段

  1. componentWillUnmount:组件从页面中删除的时候执行

还有一个特殊的生命周期函数:componentWillReceiveProps 函数。

componentWillReceiveProps:子组件接收到父组件传递过来的参数,父组件render函数重新被执行,这个生命周期就会被执行。

  1. 可以利用生命周期函数的一些特性对程序的性能进行优化: 例如父组件有个输入框,输入框的值传递props到子组件,引起子组件重新调用render函数,即是重新渲染,但是我们不希望我们输入时,子组件就在不停的调用render,这样会引起性能损耗,我们只是希望当我们输入完成之后,子组件的render调用就行了,在这种情况下面,我们就可以利用生命周期来实现性能优化。我们监听子组件的更新周期,对传递的props进行前后比较:
 shouldComponentUpdate(nextProps,nextState){
        if(nextProps.content !== this.props.content){
            return true
        }else{
            return false
        }
}//shouldComponentUpdate有两个参数:nextProps:变化后的属性;nextState:变化后的状态;
复制代码

未完待续...

参考自React官网和技术胖博客

关注下面的标签,发现更多相似文章
评论