zoukankan      html  css  js  c++  java
  • 组件实例三大属性

    组件实例三大属性

    一、三大属性之一:state

    1、在构造器中初始化state

    默认状态下React.Components会给我们定义构造器(类似于无参构造函数一样),但是默认是把state设置为null的,那么如果我们要自定义初始化的state的话,那么我们就要像(有参构造函数一样)自定义构造函数了

     

    如何自定义构造函数呢?

    先上代码:

    class Weather extends React.Component {
            constructor(props) {
                super(props)
                this.state = {isHot: false}
                this.changeWeacher = this.changeWeacher.bind(this)
            }
            render() {
                return <h1 onClick={this.changeWeacher}>今天天气很{this.state.isHot ? '炎热' : '凉爽'}</h1>
            }
            // 不写 function
            changeWeacher() {
                console.log(this)
            }
        }
     

    其中的构造函数模块:

     constructor(props) {
         super(props)
         this.state = {isHot: false}
         this.changeWeacher = this.changeWeacher.bind(this)
    }

    一个重要的细节:

    自定义构造函数,必须要执行

    super(props)

    为什么?

    并且 为什么super()要放在构造函数最上面执行呢?

    ES6语法中,super指代的其实是父类的构造函数,也就是React.Component的构造函数了,

    • 在你调用super( ) 之前,你无法在构造函数中使用this

    • 执行 super(props) 可以使基类 React.Component 初始化 this.props。

    • 另外一个疑问:有时候我们不传 props,只执行 super(),或者没有设置 constructor 的情况下,依然可以在组件内使用 this.props,为什么呢?

      • 其实 React 在组件实例化的时候,马上又给实例设置了一遍 props:

        // React 内部
        const instance = new YourComponent(props);
        instance.props = props;
      • 虽然 React 会在组件实例化的时设置一遍 props,但在 super 调用一直到构造函数结束之前,this.props 依然是未定义的(直接报错了)

        class Button extends React.Component {
          constructor(props) {
            super(); // ? 我们忘了传入 props
            console.log(props);      // ✅ {}
            console.log(this.props); // ? undefined
          }
          // ...
        }

     

     

    然后因为state要是对象的模式,所以通过以下语句进行初始化

     this.state = {isHot: false}

     

    拓展:类中的方法!

     render() {
       return <h1 onClick={this.changeWeacher()}>今天天气很{this.state.isHot ? '炎热' : '凉爽'}</h1>
     }

    如果是通过 this.changeWeacher() 的话 报错

    因为在{ } 内是js语句,所以this.changeWeacher()是直接执行了函数,那么onclick得到的就是这个函数执行的结果了,所以这种方式的话,那么这个函数是一个柯里化函数

    • 柯里化函数:该函数接收一个函数作为参数(比如数组的map方法),或者是该函数返回值是一个函数

    如果我们定义函数的时候直接通过:

    changeWeacher() {
        console.log(this)
        }

    那么这个时候this是undefined的,因为在babal的模式下,也就是严格模式下,changeWeacher函数里面的this是直接执行全局的,但是严格模式下不允许这个发生,所以执行的就是undefined

    • 代码中通过如下方式(通过bind显示硬绑定this,让this执行的是该class类的实例了)

    this.changeWeacher = this.changeWeacher.bind(this)

     

    在函数中访问和修改state

    当该函数的this不管是通过 箭头函数 还是通过显示绑定的方式让this执行了该实例的话,就可以通过this来访问state了

    changeWeacher() {
        const isHot = this.state.isHot
        this.setState({isHot: !isHot}) 
    }

    并且只能通过 this.setState的方式改变state,直接赋值操作改变的话,改变不了状态的(赋值操作可以改变页面数值,但是内部的状态是没有改变的)

     

    state的简写方式

    class Weather extends React.Component {
                state = {isHot: false}
    
                render() {
                    return <h1 onClick={this.changeWeacher}>今天天气很{this.state.isHot ? '炎热' : '凉爽'}</h1>
                }
    
                changeWeacher = () => {
                   const isHot = this.state.isHot
                   this.setState({isHot: !isHot}) 
                }
            }
    • 不适用构造函数初始化state,直接像定义private属性一样,直接定义类的属性

    • 通过箭头函数的方式定义函数(因为即使在babel严格模式下,箭头函数不会收到严格模式的约束,在箭头函数中使用this访问属性的话,当前作用域找不到的话,就在外面作用域找

      • 所以就可以在箭头函数的this中直接访问实例中定义的state了

     

    二、三大属性之二:props

     

    props的基本使用

    <script type="text/babel">
            class Person extends React.Component{
                render() {
                    return (
                        <ul>
                            <li>年级1:{this.props.name}</li>
                            <li>年级2:{this.props.sex}</li>
                            <li>年级3:{this.props.age}</li>
                        </ul>
                    )
                }
            }
            // ReactDOM.render(<Person age="19" />, document.getElementById('test'))
            // ReactDOM.render(<Person age={19}/>, document.getElementById('test'))
    
            const p = {name : 'gogocj', age: '19', sex: '男'}
            ReactDOM.render(<Person {...p} />, document.getElementById('test'))
        </script>
    • 在类中中直接通过this.props访问传递过来的参数

      • 如果是在jsx中的话,就要在 { } 中来访问this.props

    • 传递参数相关

      • 如果想要传输数字的话,要通过 <Person age={19}/>,也就是通过一个{ } 因为在{ }中式js语句,所以19就是js语句中的数字了

      • 通过{ ...p } 三点运算展开符的方式来传递props

     

    限制props的类型和默认值

    class Person extends React.Component{
                ........
            }
            Person.propTypes = {
                name: PropTypes.string.isRequired,
                speak: PropTypes.func
            }
            Person.defaultProps = {
                sex: '未知'
            }

    使用继承了React.Component的类自带的 propTypes属性

    • 要求是串联的:

      PropTypes.string.isRequired  // 表示类型是字符串,并且是必须传的
    • 默认值通过 自带的defaultProps属性

     

    简写方式

    上面都是直接通过Person.propTypes的方式来对规定类型限制的:

    但是Person就是当前的类,所以完全可以省略Person,直接在这个类的内部定义一个static对象就可以了

    class Person extends React.Component{
            ............
            static propTypes = {
                name: PropTypes.string.isRequired,
                speak: PropTypes.func
            }
            static defaultProps = {
                sex: '未知'
            }
    }

     

    在构造器中使用props

    constructor(props) {
        super(props)
        // 使用props
    }
    • 如果要在构造器中使用的话就必须写 super(props) ,不然在构造器中使用props的话,就会直接的报错了

    • 也就是说,构造器中不适用props就可以不定义,使用的话就要super一下

     

     

    三、三大属性之三:refs

    前言:

    React的诞生很多都是为了减少对document的使用,而我们如果在js中要获取到对应元素的话,传统的方法都是直接使用document的getlementbyid,byClass等等,到那时在React为了减少document操作,使用的是refs

     

    字符串类型的refs

    • class Demo extends React.Component{
                  showData = () => {
                     const {input01} = this.refs
                     alert(input01.value)
                  }
                  render() {
                      return (
                          <div>
                              <input id="input1" ref="input01" type="text" placeholder="点击按钮提示数据"/>
                              <button onClick={this.showData}>点我提示左侧的数据</button>
                          </div>
                      )
                  }
              }

      我们通过在jsx中,用ref来表示jsx中程序员写的虚拟DOM,但是我们通过this.refs获取到的元素并不是虚拟DOM,而是虚拟DOM转化成真实DOM之后的节点

    • 通过this.refs.input01就可以拿到这个input元素了

     

    拓展:React对原生html的相关疯转

    在原生里面使用 onclick、onblur等等,但是在React中使用的是onClick、onBlur等等

    为什么呢?

    React其实是在原生的onclick等等的基础上,进行了相关兼容性的封装,然后改了一下名字,也就是第二个单词首字母大写了,也就是onClick

     

    回到函数形式的refs

    前言:

    字符串形式的ref可能在未来就废除了,因为过多的给原生定义refs来获取该元素信息,方便但是性能太低了

     class Demo extends React.Component{
                showData = () => {
                   const {input01} = this
                   alert(input01.value)
                }
                render() {
                    return (
                        <div>
                            <input  ref={ c => this.input01 = c} type="text" placeholder="点击按钮提示数据"/>
                            <button onClick={this.showData}>点我提示左侧的数据</button>
                        </div>
                    )
                }
            }
    • 直接在ref中调用箭头函数,参数就是该元素(代码中用c表示),直接通过this.input01 = c吧这个元素挂载到this上了,因为是箭头函数,所以此时的this执行的是该类实例。

     

    使用内联函数的ref

    class Demo extends React.Component{
                 saveInput = (c) => {
                    this.input1 = c
                    console.log('@',c)
                }
                render() {
                    return (
                        <div>
                           <input ref={ this.saveInput } type="text"/>
                            <button onClick={this.showInfo}>点我</button>   
                        </div>
                    )
                }
            }

    但是这种内联函数是有一个问题的

    • saveInput中:就是在状态更新的时候会执行两次,第一次c拿到的是null,第二次拿到的才是该元素,更新指的是状态的更新,也就是再一次调用render函数,但是点击和刷新就不会出现这个问题了 ,这是因为在每次渲染render的时候都会创建一个新的函数实例,所以React清空旧的并且设置新的。

     

    另一种方式:React.createRef

    class Demo extends React.Component{
        
                myRef1 = React.createRef()
                myRef2 = React.createRef()
                
                showData1 = () => {
                   alert(this.myRef1.current.value)
                }
                showData2 = () => {
                   alert(this.myRef2.current.value)
                }
                
                render() {
                    return (
                        <div>
                            <input  ref={this.myRef1} type="text" placeholder="点击按钮提示数据1"/>
                            <button onClick={this.showData1}>点我提示左侧的数据</button>
                            <input onBlur={this.showData2}  ref={this.myRef2} type="text" placeholder="失去焦点提示数据"/>
                        </div>
                    )
                }
            }
    • ref={this.myRef} 调用之后,自动把该标签放到这个容器里面

    • 但是该容器是“专人专用”的,如果多个标签同时使用的话,那么后放进去的标签就会把前面的顶掉了

    • 虽然这个是要用多少个就要挂载多少个在实例上,但是这种方式是目前react最推荐的一种方式了

     

     

  • 相关阅读:
    Smarty简介
    简易调用及实例化视图
    简易调用及实例化模型
    简易调用及实例化控制器
    MVC错误(一)
    单一入口及MVC目录规范
    MVC各个层的作用
    MVC工作流程
    【学习笔记】字符串—马拉车(Manacher)
    【题解】邻值查找 [CH1301]
  • 原文地址:https://www.cnblogs.com/SCAU-gogocj/p/15330552.html
Copyright © 2011-2022 走看看