1.组件的分类和结构

1.1 函数式组件

函数式组件:通过ES5的构造函数定义的组件,不能定义state状态数据,只用于模板展示,不用于数据的交互,也叫无状态组件。函数式组件return返回的是组件模板 函数式组件的结构如下:

function MyCom1(){
        return <div>这是函数式组件的组件模板</div>
      }
1.2 类组件

类组件:通过ES6的class类定义的组件,可以定义state状态数据,用于数据逻辑交互,也叫做有状态组件。**类组件的模板需要通过render函数return出去。**类组件的结构如下:

class MyCom2 extends React.Component{
        // 类组件的模板需要通过render函数return出去
        render(){
           return <div>这是类组件的组件模板</div>
        }
      }

注意:函数式组件和类组件的组件名都是大驼峰命名,如MyCom

2.组件状态

由于函数式是无状态的,只有类组件中可以定义组件状态state

2.1 类组件状态数据的定义

类组件状态数据state定义有两种方法

2.1.1 在组件中直接定义赋值
state = {
        name:"张三"
 }
2.1.1 在构造器中定义state状态数据

注意:在构造器中定义state状态数据会把组件中直接定义的state覆盖掉,在构造器中定义的state优先级会比直接在组件中定义的state要高。

constructor(){
        super()//必选,调用父类构造器,用于继承
        console.log(this); //当前组件
       this.state={
         age:10
        }
      }
2.2 组件中的函数,修改this指向为当前组件的三种方式

组件中的函数,默认this为undefined,使this指向当前组件的三种方式:

2.2.1 定义函数时使用箭头函数定义
nameChange1(){
        console.log(this);//undefined
        // 组件中的函数,默认this为undefined,不是当前组件
      }
      nameChange2=()=>{
        console.log(this);//当前组件
      }
2.2.2 在模板中调用函数时使用bind修改this
<input value={this.state.name} onChange={this.nameChange3.bind(this)} />
2.2.3 在构造器中初始化修改函数this指向
constructor(){
        super()//必选,调用父类构造器,用于继承
        console.log(this); //当前组件
   // 在组件的构造器中提前修改函数的this指向,模板中调用函数内部this就有值
        this.nameChange4 = this.nameChange4.bind(this)
      }
2.2.4 在模板中绑定函数,使用箭头函数直接在默认中实现
<button onClick={()=>{
                    console.log(this);
                  }}>求和</button>
2.3 组件模板中调用函数向函数中传参

组件模板中调用函数向函数中传参的两种方式:

2.3.1 使用data-自定义属性传值,函数中使用e.target.dataset接收数据

注意:data-属性传入的值只能一个一个的传并且传的使字符串并不能传数组对象结构

<button onClick={this.add}  data-a="3" data-b="4" >求和</button>
add(...params){
        // 使用自定义属性传参,函数的参数默认是事件信息对象e
          console.log(params[0].currentTarget.dataset);
          var data = params[0].currentTarget.dataset
          console.log(data.a*1 + data.b*1);
      }
2.3.2 调用函数时,使用bind修改this,并传参
<button onClick={this.add1.bind(this,3,4)}>求和</button>
add1(...params){
        // 使用bind函数传参,函数的参数前边是bind传入的参数,最后一个参数是事件对象e
          console.log(params[0],params[1],params[2]);
      }
2.4 在组件的render渲染函数中不要更新状态数据state

在render函数中不能写数据更新setState,因为数据更新会调用render视图更新,如果在render中再调用数据更新,则会进去死循环

render(){
        console.log("render");
        // 特别注意:在render函数中不能写数据更新setState,因为数据更新会调用render试图更新,如果在render中再调用数据更新,则会进去死循环
            this.setState({
                name:"lisi"
            })
            return (
              <div>
                {/*在模板中调用state和函数都需要this打点调用*/}
                  <input value={this.state.name} onChange={this.nameChange1} />
                  <input value={this.state.name} onChange={this.nameChange2} />
                  <input value={this.state.name} onChange={this.nameChange3.bind(this)} />
                  <input value={this.state.name} onChange={this.nameChange4} />
                  <button onClick={this.add}  data-a="3" data-b="4" >求和</button>
                  <button onClick={this.add1.bind(this,3,4)}>求和</button>
                  <button onClick={()=>{
                    console.log(this);
                  }}>求和</button>
              </div>
            )
      }
    }

3.react生命周期函数

有状态的类组件拥有生命周期钩子,函数式组件无生命周期钩子

  • constructor 创建周期函数
  • getDerivedStateFromProps 收到数据更新
  • componentDidMount 渲染后
  • shouldComponentUpdate 控制组件是否更新
  • getSnapshotBeforeUpdate 组件将要更新
  • render 组件正在渲染
  • componentDidUpdate 组件已经更新
  • componentWilUnmount 组件将要移除
3.1 componentDidMount 只会在组件初始化时执行一次,render在每次数据更新都会执行
3.2 render shouldComponentUpdate getDerivedStateFromProps getSnapshoutBeforeUpdate 这四个钩子函数要求必须有返回值
3.2.1 render的返回值是模板
render(){
                console.log("render 渲染")
                return <button onClick={()=>{
                    this.setState({
                        count: this.state.count + 1
                    })
                }}>{this.state.count}</button>
            }
3.2.2 shouldComponentUpdate 的返回值

shouldComponentUpdate:控制组件更新,函数的返回值必须是bool值,true允许更新,执行render,false禁止更新

shouldComponentUpdate(nextProps, nextState) {
                console.log("shouldComponentUpdate 控制组件更新")
      // 这个函数要求返回bool值, true允许更新,执行render, false禁止更新
                return true
            }
3.2.3 getDerivedStateFromProps 函数返回值

getDerivedStateFromProps:收到数据更新,函数的返回值可以是null或对象,如果返回的是对象,返回的对象数据会更新到state状态中

static getDerivedStateFromProps(props, state) {
                console.log("getDerivedStateFromProps")
                // 这个钩子函数必须要有return, 返回值可以是null或对象
                // return null
                // 如果返回的是对象, 返回的对象数据会更新到state状态中
                return {
                    count: 100
                }
            }
3.2.4 getSnapshotBeforeUpdate函数返回值

getSnapshoutBeforeUpdate:组件将要更新,函数的返回值会传入componentDidUpdate组件已经更新的函数的第三个参数

getSnapshotBeforeUpdate(prevProps, prevState) {
                console.log("getSnapshotBeforeUpdate")
                // 这个钩子函数也要求必须有返回值
                // return null
         // 这个函数的返回值会传入 componentDidUpdate 函数的第三个参数中
                return {
                    name: "张三"
                }
            }
componentDidUpdate(prevProps, prevState, data) {
                console.log("componentDidUpdate 已经更新", data)
            }

4.组件传值

4.1 父传子
4.1.1props传值
4.1.1.1 函数式组件

函数式组件通过函数的参数props接收父组件通过属性传入的数据

<MyCom1 name="张三"/>
                
            function  MyCom1(props) {
            // 函数式组件通过函数的参数props接收父组件通过属性传入的数据
            console.log(props)
            return <div>组件1-{props.name}</div>
        }
4.1.1.2 类组件

类组件通过构造器的参数props接收父组件通过属性传入的数据

组件结构:

ReactDOM.render(
            <div>
                <MyCom1 name="张三"/>
                <MyCom2 age="20"/>
            </div>,
            document.getElementById('example')
        )
class MyCom2 extends React.Component{
            constructor(props) {
                super(props);
                //类组件通过构造器的参数props接收父组件通过属性传入的数据
                console.log(props)
                // props.age = 30  props是只读的,不能改
                this.state = {sex: "男"}
            }
            render() {
                // 类组件中的props数据在模板中使用this打点调用
                return <div>组件2-{this.props.age}-{this.state.sex}</div>
            }
        }
4.1.2 插槽传值

插槽数据会被传入子组件的props对象中,有三种情况:

  • 组件没有传入插槽数据,props中就没有children字段
  • 组件传入的插槽数据是一个标签(根标签)或一段数据,props中children字段值就是传入的插槽数据
  • 组件传入的操作数据是多个标签或标签于数据的混合,props中children就是一个数组
function MyCom1(props) {
            console.log(props)
            return <div>组件1-{props.children}</div>
        }

        class MyCom2 extends React.Component{
            constructor(props) {
                super(props);
                console.log(props)
            }
            render() {
                return (
                    <div>组件2-{this.props.children}</div>
                )
            }
        }

ReactDOM.render(
            <div>
                <MyCom1></MyCom1>
                <MyCom1>插槽数据</MyCom1>
                <MyCom1>{[1,2,3,4]}</MyCom1>
                <MyCom2><a href="#">百度</a></MyCom2>
                <MyCom2>
                    <ul>
                        <li>1</li>
                        <li>2</li>
                        <li>3</li>
                    </ul>
                </MyCom2>
                <MyCom2>
                    <li>1</li>
                    <li>2</li>
                    <li>3</li>
                </MyCom2>
            </div>,
            document.getElementById('example')
        )
4.2 子传父

react中子传父原理:在父组件中定义更新函数,把函数传入子组件,在子组件中调用更新函数,通过参数把子组件数据传入父组件

class ChildCom extends React.Component{
            add = ()=>{
                // this.$emit("event", this.props.numer + 1)   vue  
                // this.triggerEvent("event", this.props.numer + 1)  小程序
                console.log(this.props)
                // react中子传父原理: 在父组件中定义更新函数,把函数传入子组件, 在子组件中调用更新函数, 通过参数把子组件数据传入父组件
                this.props.myChange(this.props.number + 1, this.props.i)
            }
            render() {
                return (
                    <div>
                        子组件: <button onClick={this.add}>{this.props.number}++</button>
                    </div>
                )
            }
        }
        // 定义父组件
        class FatherCom extends React.Component{
            state = {
                fatherList: [1,5,4,7]
            }
            changeNumber = (value, index)=>{
                console.log(value, index)
                this.state.fatherList[index] = value
                this.setState({
                    fatherList: this.state.fatherList
                })
            }
            render() {
                return (
                    <div>
                    {
                        this.state.fatherList.map((item,index)=>{
                            return <ChildCom number={item} i={index} key={index} myChange={this.changeNumber}/>
                        })
                    }
                    </div>
                )
            }
        }


        ReactDOM.render(
            <div> <FatherCom/> </div>,
            document.getElementById('example')
        )