zoukankan      html  css  js  c++  java
  • React——组件的三大核心属性【七】

    前言

    组件的三大核心属性

    内容

    state

    定义一个展示天气信息组件,通过点击切换天气信息

    理解

    1. state是组件对象最重要的属性,值是对象(可以包含多key-value组合)
    2. 组件被称为状态机,通过更新组件的state来重新渲染组件
    <!doctype html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <meta name="viewport"
              content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
        <meta http-equiv="X-UA-Compatible" content="ie=edge">
        <title>Document</title>
    </head>
    <body>
    <!--创建"容器"-->
    <div id="test">
    
    </div>
    <!--引入react核心库-->
    <script type="text/javascript" src="../js/react.development.js"></script>
    <!--引入react-dom,用于支持react操作DOM-->
    <script type="text/javascript" src="../js/react-dom.development.js"></script>
    <!--引入babel,用于将jsx转js-->
    <script type="text/javascript" src="../js/babel.min.js"></script>
    <script type="text/babel">/*一定要以text/babel来声明*/
    //1. 创建组件
    
    class Weather extends React.Component {
    
        //调用1次
        constructor(props) {
            super(props);
            //初始化状态
            this.state = { isHot: true };
            //解决changeWeather的指向问题
            this.changeWeather = this.changeWeather.bind(this)
        }
        //调用次数1+n 1是初始化,n是状态更新
        render() {
            console.log(this)
            //读取状态
            const {isHot} = this.state
            return (
                <div>
                   <h1 onClick={this.changeWeather}>今天天气 {isHot ? '热热' : '不热热'}</h1>
                </div>
            );
        }
        //点击几次调用几次
        changeWeather(){
            //状态不可直接更改需要借助内置方法(setState)进行更改
            const isHot = this.state.isHot
            this.setState({isHot:!isHot})
        }
    }
    
    //2.渲染组件到页面
    ReactDOM.render(<Weather/>,document.getElementById('test'))
    
    </script>
    </body>
    </html>
    

    简写

    <!doctype html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <meta name="viewport"
              content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
        <meta http-equiv="X-UA-Compatible" content="ie=edge">
        <title>Document</title>
    </head>
    <body>
    <!--创建"容器"-->
    <div id="test">
    
    </div>
    <!--引入react核心库-->
    <script type="text/javascript" src="../js/react.development.js"></script>
    <!--引入react-dom,用于支持react操作DOM-->
    <script type="text/javascript" src="../js/react-dom.development.js"></script>
    <!--引入babel,用于将jsx转js-->
    <script type="text/javascript" src="../js/babel.min.js"></script>
    <script type="text/babel">/*一定要以text/babel来声明*/
    //1. 创建组件
    
    class Weather extends React.Component {
        
        render() {
            const {isHot} = this.state
            return (
                <div>
                   <h1 onClick={this.changeWeather}>今天天气 {isHot ? '热热' : '不热热'}</h1>
                </div>
            );
        }
        //赋值语句+箭头函数
        changeWeather = () => {
            const isHot = this.state.isHot
            this.setState({isHot:!isHot})
        }
    }
    
    //2.渲染组件到页面
    ReactDOM.render(<Weather/>,document.getElementById('test'))
    
    </script>
    </body>
    </html>
    
    

    注意点

    1. 组件中的render方法中的this为组件实例对象
    2. 组件中自定义的方法中的为undefined,如何解决?
       2.1 前置绑定this:通过函数对象的bind()
       2.2 赋值语句+箭头函数
    3. 状态数据,不能直接修改或更新,需通过setState来变更
    

    props

    自定义用来显示一个人员信息的组件

    1. 姓名必须指定,且为字符串类型;
    2. 性别为字符串类型,如果性别没有指定,默认为男
    3. 年龄为字符串类型,且为数字类型,默认值为18

    理解

    1. 每个组件对象都会有props(properties)属性
    2. 组件标签的所有属性都保存在props中
    <!doctype html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <meta name="viewport"
              content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
        <meta http-equiv="X-UA-Compatible" content="ie=edge">
        <title>Document</title>
    </head>
    <body>
    <!--创建"容器"-->
    <div id="test"></div>
    <div id="test1"></div>
    <div id="test2"></div>
    <!--引入react核心库-->
    <script type="text/javascript" src="../js/react.development.js"></script>
    <!--引入react-dom,用于支持react操作DOM-->
    <script type="text/javascript" src="../js/react-dom.development.js"></script>
    <!--引入babel,用于将jsx转js-->
    <script type="text/javascript" src="../js/babel.min.js"></script>
    <!--引入prop-types,用于对组件标签属性进行限制-->
    <script type="text/javascript" src="../js/prop-types.js"></script>
    <script type="text/babel">/*一定要以text/babel来声明*/
    //1. 创建组件
    
    class Person extends React.Component {
        render() {
            //props是只读的,不可进行修改
            const {name,age,sex} = this.props
            return (
                <div>
                    <ul>
                        <li>姓名:{name}</li>
                        <li>年龄:{age}</li>
                        <li>性别:{sex}</li>
                    </ul>
                </div>
            );
        }
    }
    
    //对标签属性进行类型,必要性限制
    Person.protoType = {
        name: PropTypes.string.isRequired, // 限制name必传且类型为string
        age: PropTypes.number,
        sex: PropTypes.string,
        speak: PropTypes.func
    }
    
    //指定默认标签属性值
    Person.defaultProps = {
        sex: "男",
        age: 18
    }
    
    function speak() {
        return "哈哈哈哈"
    }
    
    //2.渲染组件到页面
    const p = {name:"张三", age:66, sex:'男'}
    ReactDOM.render(<Person name="tom" age={19} sex="男" speak={speak}/>,document.getElementById('test'))
    ReactDOM.render(<Person name="jim" age="10" sex="男"/>,document.getElementById('test1'))
    //语法糖
    ReactDOM.render(<Person {...p}/>,document.getElementById('test2'))
    
    </script>
    </body>
    </html>
    
    

    简写

    <!doctype html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <meta name="viewport"
              content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
        <meta http-equiv="X-UA-Compatible" content="ie=edge">
        <title>Document</title>
    </head>
    <body>
    <!--创建"容器"-->
    <div id="test"></div>
    <div id="test1"></div>
    <div id="test2"></div>
    <!--引入react核心库-->
    <script type="text/javascript" src="../js/react.development.js"></script>
    <!--引入react-dom,用于支持react操作DOM-->
    <script type="text/javascript" src="../js/react-dom.development.js"></script>
    <!--引入babel,用于将jsx转js-->
    <script type="text/javascript" src="../js/babel.min.js"></script>
    <!--引入prop-types,用于对组件标签属性进行限制-->
    <script type="text/javascript" src="../js/prop-types.js"></script>
    <script type="text/babel">/*一定要以text/babel来声明*/
    //1. 创建组件
    
    class Person extends React.Component {
        // constructor(props) {
        //     //构造器是否接收props,是否传递给super,取决于:是否希望在构造器中通过this访问props
        //     super(props);
        // }
        //对标签属性进行类型,必要性限制
        static protoType = {
            name: PropTypes.string.isRequired, // 限制name必传且类型为string
            age: PropTypes.number,
            sex: PropTypes.string
        }
    
        //指定默认标签属性值
        static defaultProps = {
            sex: "男",
            age: 18
        }
    
        render() {
            //props是只读的,不可进行修改
            const {name,age,sex} = this.props
            return (
                <div>
                    <ul>
                        <li>姓名:{name}</li>
                        <li>年龄:{age}</li>
                        <li>性别:{sex}</li>
                    </ul>
                </div>
            );
        }
    }
    
    
    ReactDOM.render(<Person name="tom" />,document.getElementById('test'))
    
    </script>
    </body>
    </html>
    
    

    函数式组件使用props

    <!doctype html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <meta name="viewport"
              content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
        <meta http-equiv="X-UA-Compatible" content="ie=edge">
        <title>Document</title>
    </head>
    <body>
    <!--创建"容器"-->
    <div id="test"></div>
    <div id="test1"></div>
    <div id="test2"></div>
    <!--引入react核心库-->
    <script type="text/javascript" src="../js/react.development.js"></script>
    <!--引入react-dom,用于支持react操作DOM-->
    <script type="text/javascript" src="../js/react-dom.development.js"></script>
    <!--引入babel,用于将jsx转js-->
    <script type="text/javascript" src="../js/babel.min.js"></script>
    <!--引入prop-types,用于对组件标签属性进行限制-->
    <script type="text/javascript" src="../js/prop-types.js"></script>
    <script type="text/babel">/*一定要以text/babel来声明*/
    //1. 创建组件
    function Person(props) {
        const {name, age, sex} = props
        return (
            <div>
                <ul>
                    <li>姓名:{name}</li>
                    <li>年龄:{age}</li>
                    <li>性别:{sex}</li>
                </ul>
            </div>
        )  ;
    }
    
        //对标签属性进行类型,必要性限制
         Person.protoType = {
            name: PropTypes.string.isRequired, // 限制name必传且类型为string
            age: PropTypes.number,
            sex: PropTypes.string
        }
    
        //指定默认标签属性值
         Person.defaultProps = {
            sex: "男",
            age: 18
        }
    
    ReactDOM.render(<Person name="tom" sex="女" age={18}/>,document.getElementById('test'))
    
    </script>
    </body>
    </html>
    
    

    注意点

    1. 通过标签属性从组件外向组件内传递变化的数据
    2. 注意: 组件内部不要修改props数据
    3. 内部通过this.props.xx读取某个属性值
    4. props中的属性值进行类型限制和必要性限制
       4.1 React v15.5 开始已弃用
            Person.propTypes = {
             name: React.PropTypes.string.isRequired,
             age: React.PropTypes.number
            }
       4.2 使用prop-types库进限制(需要引入prop-types库)
           Person.propTypes = {
            name: PropTypes.string.isRequired,
            age: PropTypes.number. 
           }
    5. 扩展属性: 将对象的所有属性通过props传递
       <Person {...person}/>
    6. 默认属性值
       Person.defaultProps = {
        age: 18,
        sex:'男'
       }
    
    

    ref

    1. 点击按钮, 提示第一个输入框中的值
    2. 当第2个输入框失去焦点时, 提示这个输入框中的值

    理解

    组件内的标签可以定义ref属性来标识自己

    字符串类型ref

    <!doctype html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <meta name="viewport"
              content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
        <meta http-equiv="X-UA-Compatible" content="ie=edge">
        <title>Document</title>
    </head>
    <body>
    <!--创建"容器"-->
    <div id="test"></div>
    <!--引入react核心库-->
    <script type="text/javascript" src="../js/react.development.js"></script>
    <!--引入react-dom,用于支持react操作DOM-->
    <script type="text/javascript" src="../js/react-dom.development.js"></script>
    <!--引入babel,用于将jsx转js-->
    <script type="text/javascript" src="../js/babel.min.js"></script>
    <script type="text/babel">/*一定要以text/babel来声明*/
    class Demo extends React.Component {
    
        //左侧
        showData = () => {
            const { input1 } = this.refs
            alert(input1.value)
        }
    
        //右侧
        showData2 = () => {
            const { input2 } = this.refs
            alert(input2.value)
        }
        render() {
            return (
                <div>
                    <input ref="input1" type="text" placeholder="点击按钮提示数据"/> &nbsp;
                    <button  onClick={this.showData}>点我提示左侧数据</button>
                    <br/>
                    <hr/>
                    <input onBlur={this.showData2} ref="input2" type="text" placeholder="失去焦点提示数据"/>
                </div>
            );
        }
    }
    
    ReactDOM.render(<Demo/>, document.getElementById("test"))
    
    
    /**
     * string类型的ref是过时的API
     * https://react.docschina.org/docs/refs-and-the-dom.html#legacy-api-string-refs
     *
     * https://github.com/facebook/react/pull/8333#issuecomment-271648615
     */
    
    </script>
    </body>
    </html>
    
    

    回调函数类型ref

    <!doctype html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <meta name="viewport"
              content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
        <meta http-equiv="X-UA-Compatible" content="ie=edge">
        <title>Document</title>
    </head>
    <body>
    <!--创建"容器"-->
    <div id="test"></div>
    <!--引入react核心库-->
    <script type="text/javascript" src="../js/react.development.js"></script>
    <!--引入react-dom,用于支持react操作DOM-->
    <script type="text/javascript" src="../js/react-dom.development.js"></script>
    <!--引入babel,用于将jsx转js-->
    <script type="text/javascript" src="../js/babel.min.js"></script>
    <script type="text/babel">/*一定要以text/babel来声明*/
    class Demo extends React.Component {
    
        //左侧
        showData = () => {
            const {input1} = this
            alert(input1.value)
        }
    
        //右侧
        showData2 = () => {
            const {input2} = this
            alert(input2.value)
        }
        render() {
            return (
                <div>
                    <input ref={currentNode => this.input1 = currentNode} type="text" placeholder="点击按钮提示数据"/> &nbsp;
                    <button  onClick={this.showData}>点我提示左侧数据</button>
                    <br/>
                    <hr/>
                    <input  ref={currentNode => this.input2 = currentNode} onBlur={this.showData2}  type="text" placeholder="失去焦点提示数据"/>
                </div>
            );
        }
    }
    
    ReactDOM.render(<Demo />, document.getElementById("test"))
    
    
    
    </script>
    </body>
    </html>
    
    
    

    如果 ref 回调函数是以内联函数的方式定义的,在更新过程中它会被执行两次,第一次传入参数 null,然后第二次会传入参数 DOM 元素。这是因为在每次渲染时会创建一个新的函数实例,所以 React 清空旧的 ref 并且设置新的。通过将 ref 的回调函数定义成 class 的绑定函数的方式可以避免上述问题,但是大多数情况下它是无关紧要的

    <!doctype html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <meta name="viewport"
              content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
        <meta http-equiv="X-UA-Compatible" content="ie=edge">
        <title>Document</title>
    </head>
    <body>
    <!--创建"容器"-->
    <div id="test"></div>
    <!--引入react核心库-->
    <script type="text/javascript" src="../js/react.development.js"></script>
    <!--引入react-dom,用于支持react操作DOM-->
    <script type="text/javascript" src="../js/react-dom.development.js"></script>
    <!--引入babel,用于将jsx转js-->
    <script type="text/javascript" src="../js/babel.min.js"></script>
    <script type="text/babel">/*一定要以text/babel来声明*/
    class Demo extends React.Component {
    
        state = {isHot:true}
    
        changeWeather = () => {
            const {isHot} = this.state
            this.setState({isHot:!isHot})
        }
    
        //左侧
        showData = () => {
            const {input1} = this
            alert(input1.value)
        }
    
        saveInput = (c) => {
            this.input1 = c;
            console.log('@',c);
        }
    
        render() {
            const {isHot} = this.state
            return (
                <div>
                    <h2>今天天气很{isHot ? '炎热' : '凉爽'}</h2>
                    <button onClick={this.changeWeather}>点击切换天气</button>
                    {/*<input ref={(currentNode) => { this.input1 = currentNode; console.log('@',currentNode);} }  type="text" placeholder="点击按钮提示数据"/> &nbsp;*/}
                    <input ref={this.saveInput}  type="text" placeholder="点击按钮提示数据"/> &nbsp;
                    <button  onClick={this.showData}>点我提示左侧数据</button>
                </div>
            );
        }
    }
    
    ReactDOM.render(<Demo />, document.getElementById("test"))
    
    </script>
    </body>
    </html>
    
    
    

    createRef

    <!doctype html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <meta name="viewport"
              content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
        <meta http-equiv="X-UA-Compatible" content="ie=edge">
        <title>Document</title>
    </head>
    <body>
    <!--创建"容器"-->
    <div id="test"></div>
    <!--引入react核心库-->
    <script type="text/javascript" src="../js/react.development.js"></script>
    <!--引入react-dom,用于支持react操作DOM-->
    <script type="text/javascript" src="../js/react-dom.development.js"></script>
    <!--引入babel,用于将jsx转js-->
    <script type="text/javascript" src="../js/babel.min.js"></script>
    <script type="text/babel">/*一定要以text/babel来声明*/
    class Demo extends React.Component {
    
        // React.createRef调用后可以返回一个容器,该容器可以存储被ref所标识的节点,该容器是专人专用的
        myRef = React.createRef()
        myRef2 = React.createRef()
        //左侧
        showData = () => {
            alert(this.myRef.current.value)
        }
    
        //右侧
        showData2 = () => {
            alert(this.myRef2.current.value)
        }
        render() {
            return (
                <div>
                    <input ref={this.myRef} type="text" placeholder="点击按钮提示数据"/> &nbsp;
                    <button  onClick={this.showData}>点我提示左侧数据</button>
                    <input onBlur={this.showData2} ref={this.myRef2} type="text" placeholder="=失去焦点显示数据"/> &nbsp;
                </div>
            );
        }
    }
    
    ReactDOM.render(<Demo />, document.getElementById("test"))
    
    
    
    </script>
    </body>
    </html>
    
    
    

    注意点

    1.  string类型的ref是过时的API,可能会在未来版本被移除,建议使用回调函数或createRef API来代替。
        <input ref="input1"/>
    
    2. 回调函数类型的ref
       <input ref={(c)=>{this.input1 = c}} />
       2.1 ref 回调函数是以内联函数的方式定义的,在更新过程中它会被执行两次,第一次传入参数 null,然后第二次会传入参数 DOM 元素
           <input ref={this.saveInput} /> //通过将 ref 的回调函数定义成 class 的绑定函数的方式可以避免上述问题
    
    3. createRef创建ref容器
       myRef = React.createRef() 
       <input ref={this.myRef}/>
     
    

    事件处理

    1.通过onXxx属性指定事件处理函数(注意大小写)
      1) React使用的是自定义(合成)事件, 而不是使用的原生DOM事件___兼容性
      2) React中的事件是通过事件委托方式处理的(委托给组件最外层的元素)___高效性
    2.通过event.target得到发生事件的DOM元素对象___不要过度使用ref
    
    <!doctype html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <meta name="viewport"
              content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
        <meta http-equiv="X-UA-Compatible" content="ie=edge">
        <title>Document</title>
    </head>
    <body>
    <!--创建"容器"-->
    <div id="test"></div>
    <!--引入react核心库-->
    <script type="text/javascript" src="../js/react.development.js"></script>
    <!--引入react-dom,用于支持react操作DOM-->
    <script type="text/javascript" src="../js/react-dom.development.js"></script>
    <!--引入babel,用于将jsx转js-->
    <script type="text/javascript" src="../js/babel.min.js"></script>
    <script type="text/babel">/*一定要以text/babel来声明*/
    class Demo extends React.Component {
    
        /**
         1.	通过onXxx属性指定事件处理函数(注意大小写)
             1)	React使用的是自定义(合成)事件, 而不是使用的原生DOM事件___兼容性
             2)	React中的事件是通过事件委托方式处理的(委托给组件最外层的元素)___高效性
         2.	通过event.target得到发生事件的DOM元素对象___不要过度使用ref
         *
         */
    
        // 创建ref容器
        myRef = React.createRef()
        myRef2 = React.createRef()
    
    
        //左侧
        showData = () => {
            alert(this.myRef.current.value)
        }
    
        //右侧
        showData2 = (event) => {
            alert(event.target.value)
        }
        render() {
            return (
                <div>
                    <input ref={this.myRef} type="text" placeholder="点击按钮提示数据"/> &nbsp;
                    <button  onClick={this.showData}>点我提示左侧数据</button>
                    <input onBlur={this.showData2} type="text" placeholder="=失去焦点显示数据"/> &nbsp;
                </div>
            );
        }
    }
    
    ReactDOM.render(<Demo />, document.getElementById("test"))
    
    
    
    </script>
    </body>
    </html>
    
    
    
    学无止境,谦卑而行.
  • 相关阅读:
    AOP编程之cglib动态代理:进阶一
    16-python基础5-文件读写操作
    13-python基础2-条件和循环
    12-python基础1-python概述
    11-linux基础八-正则表达式
    07-linux基础四-系统监控和硬盘分区
    06-linux基础三-文件操作和系统启动流程
    05-linux基础二-用户和权限操作
    04-linux基础一概述和简单命令
    03-网络通信原理
  • 原文地址:https://www.cnblogs.com/wangyang0210/p/14422474.html
Copyright © 2011-2022 走看看