react定义组件&组件实例的三大属性

176 阅读3分钟

react定义组件&组件实例的三大属性

复杂和简单的定义就是:复杂组件有状态(state)

函数式组件(简单式组件)

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <link rel="stylesheet" href="../favicon.ico">
    <!-- 这里刷新不出来 就强制刷新  shift+刷新 -->
</head>
<body>
    <!-- 准备好一个容器  -->
    <div class="test">

    </div>
    <!-- 引入react核心库 -->
    <script src="../js/react.development.js"></script>
    <!-- 引入react-dom 用于支持react操作DOM -->
    <script src="../js/react-dom.development.js"></script>
    <!-- 引入Babel 用于将jsx转为js -->
    <script src="../js/babel.min.js"></script>
    <script type="text/babel">
        // babel 翻译 处理之后 会开启严格模式(不允许自定义的函数 this指向window)
        function MyComponents(){
            console.log(this);  //此处的this是undefined 因为Babel编译后开启了严格模式
            return <h1>我是用函数定义的组件(适用于【简单组件】的定义)</h1>
        }
        // 组件一定是一个标签 并且标签的首字母必须大写  标签必须闭合(jsx的规定  )
        ReactDOM.render(<MyComponents/>,document.querySelector('.test'));
        /*
         执行了ReactDOM.render发生了什么
            React解析组件标签,找到了MyComponent组件
            发现组件是使用函数定义的,随后调用该函数,将函数返回的虚拟DOM转为真实DOM,之后呈现在页面中
        */
    </script>
</body>
</html>

类式组件(复杂式组件)

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    <div class="test">

    </div>
    <script src="../js/react.development.js"></script>
    <script src="../js/react-dom.development.js"></script>
    <script src="../js/babel.min.js"></script>
    <script type="text/babel">
        // 创建类式组件
        // 必须要有继承、render和返回值
        class MyComponents extends React.Component {
            //  render放在了类的原型对象上,供实例使用
            render() {
                // render中的this是:mycomponent的实例对象==MyComponent组件实例对象
                console.log(this);
                return <h2>我是用类定义的组件(适用于【复杂组件】的定义)</h2>
            }
        }
        // 渲染组件到页面
        // 注意这里的两个render是不一样的
        ReactDOM.render(<MyComponents/>,document.querySelector('.test'))
        /*
         执行了ReactDOM.render发生了什么
            React解析组件标签,找到了MyComponent组件
            发现组件是使用类定义的,随后new出来MyComponent类的实例,并通过该实例调用到类的原型上的render方法
            将render返回的虚拟DOM转为真实DOM,之后呈现在页面中
          */
    </script>
</body>
</html>

组件实例的三大核心属性1:state

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    <div class="test">

    </div>
    <script src="./js/react.development.js"></script>
    <script src="./js/react-dom.development.js"></script>
    <script src="./js/babel.min.js"></script>
    <script type="text/babel">
        // 创建组件
        class Weather extends React.Component {

            // 构造器调用一次
            constructor(props){
                // 关于this的操作 super必须方法最前方
                super(props);
                // 借助构造器初始化状态
                this.state={isHot:false };
                // bind会生成一个新的函数,并且可以改变this的指向
                // 解决了changeWeather中的this指向问题
                this.changeWeather=this.changeWeather.bind(this)
            }

            // render调用n+1次  1是初始化的调用 n是点击的切换的次数
            render () {
                // console.log(this);
                // 读取状态    注意这里的花括号 表示的是在state中创建一个对象isHot
                const {isHot}=this.state;
                // 注意这里是onClick 并没有调用函数  并且用的是花括号
                // 这里并不可以直接调用,changeWeather是供实例使用的,所以这里要用this
                // 从this里面查找changeWeather
                return <h2 onClick={this.changeWeather}>今天的天气很{isHot?'炎热':'凉爽'}</h2>
            }

            // changeWeather 点击几次就调用几次
            changeWeather(){
                // changeWeather放在了Weather的原型对象上,供实例使用
                // changeWeather是onClick的回调,所以并不是实例的回调,而是直接调用
                // 直接调用的this指向应该是window,但是有严格模式
                // class类中的方法默认开启了局部的严格模式,并且在Babel里面也是严格模式,所以changWeather中的this就是undefined
                console.log(this.state.isHot);
                // 注意state是不可以随便进行更改的 需要借助一个内置的API进行更改
                const isHot=this.state.isHot;
                // this.state.isHot=!isHot;  //直接更改
                // 只要通过合法的方式  更改state react就会重新调用一次render
                // setState 只是合并了状态  而不是替换
                this.setState({isHot:!isHot});

            }
        }
        ReactDOM.render(<Weather/>,document.querySelector('.test'))
    </script>
</body>
</html>

代码的简写(这里只写了script里面的代码)

    <script type="text/babel">
        class Weather extends React.Component{
            // 在类中可以直接进行赋值语句
            state={isHot:false};
            render(){
                const {isHot}=this.state;
                return <h2 onClick={this.changeWeather}>今天的天气很{isHot?"炎热":"凉爽"}</h2>
            }
            // 自定义的函数 主要是:使用在事件回调
            // 这里一定要使用箭头函数 因为箭头函数没有this指向 this是外层的
            // 注意这里是 用赋值语句创建了一个函数
            changeWeather=()=>{
                  const isHot=this.state.isHot;
                this.setState({isHot:!isHot})
            }
        }
        ReactDOM.render(<Weather/>,document.querySelector('.test'))
    </script>

js对象解构赋值:

es6的写法:const {xxx}=this.state,const{}说明接受的是一个对象

其实相当于:const xxx=this.state.xxx

点击事件的三种使用方法:

Snipaste_2022-04-17_16-32-09.jpg

react使用规则:所有原生里面以“on”开头的事件,都要用一下写法(onclick-->onClick;onblur-->onBlur)

总结

  1. state是组件对象中最重要的属性,值是对象(可以包含多个key-value的组合)

  2. 组件被称为“状态机”,通过更新组件的state来更新对应的页面显示(重新渲染组件)

  3. 组件中render方法中的this为组件实例对象

  4. 组件自定义的方法中this俄日undefined

    1)通过强制绑定this(函数对象的bind())

    2)箭头函数 (通过赋值语句)

  5. 状态数据,不能直接修改或更新(通过setState)

组件里面维护着状态,状态里面存着数据,在更新里面的数据时,组件就进行渲染

组件实例的三大核心属性2:props

使用方法

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    <div class="test">

    </div>
    <div class="test2">

    </div>

    <script src="./js/react.development.js"></script>
    <script src="./js/react-dom.development.js"></script>
    <script src="./js/babel.min.js"></script>
    <!-- 引入prop-types,用于对组件标签属性进行限制 -->
    <script src="./js/prop-types.js"></script>
    <script type="text/babel">
        class Person extends React.Component{
            render(){
                console.log(this);
                const {name,age,sex} =this.props
                // props是只读的
                // this.props.name='jack'  //这里代码会报错,props进行了更改
                return (
                    <ul>
                        <li>姓名:{name}</li>
                        <li>性别:{sex}</li>
                        <li>年龄:{age+1}</li>  
                        
                    </ul>
                )
            }
        }
        // 对组件进行规则限制
        // 这里propType是react组件里面的规矩 并且p小写
        Person.propTypes = {
            // react里面的内置属性 设置属性的数据类型
            // 引入库文件 注意这里用大写 
            // string 表示组件的内置属性必须是字符形式,isRequired表示必须要填写
            name: PropTypes.string.isRequired,
            age: PropTypes.number,
            sex: PropTypes.string,
            speak:PropTypes.func  //限制speak为函数
        }
        // 指定默认标签属性值
        Person.defaultProps = {
            name:'Seven',
            age:19
        }

        // 1.对传递的标签属性进行类型限制
        // 2.对某一个属性添加一个默认值
        
        // 渲染组件到页面
        // 这里age若想是number型数据 就要加花括号 react没有number数据 但是js中有,所有使用{}
        ReactDOM.render(<Person  sex="女"/>,document.querySelector(".test"))
        const p ={name:'jerry',sex:"男",age:20}
        // ReactDOM.render(<Person name={p.name} />,document.querySelector(".test2"))
        // {...p}相当于39的语法糖 但是获取到属性名必须一致 不然获取不到信息
        // 这里的花括号表示花括号里面的代码是js  这里并不是{...p}展开运算符展开了对象
        // Babel和react加在一起就可以使用...p展开一个对象 但是仅仅适用于标签属性的传递 其他地方都不可以 
        ReactDOM.render(<Person {...p}/>,document.querySelector(".test2"))  //批量的传递标签属性  传递标签==传递props
    
    </script>
</body>
</html>

简写方式:

    <script type="text/babel">
        class Person extends React.Component{
            // 将标签上的属性添加给Person类 而不是实例上
            // 对标签属性进行类型,必要性的限制
            static propTypes={
            name:PropTypes.string.isRequired,
            age:PropTypes.number,
            sex:PropTypes.string,
            speak:PropTypes.func,
            }
            static defaultProps={
                name:'Seven',
                sex:'女'
            }

            render(){
                const {name,age,sex} = this.props;
                return (
                    <ul>
                        <li>name:{name}</li>
                        <li>age:{age+1}</li>
                        <li>sex:{sex}</li>
                    </ul>
                )
            }
        }
        ReactDOM.render(<Person name="tom" age={20} sex="女" />,document.querySelector('.test'))
        const p={name:'jerry',age:19,sex:"女"}
        ReactDOM.render(<Person {...p} />,document.querySelector('.test2'))
    </script>

将对标签的限制放在了类里面。

展开运算符的复习:

    <script>
        let arr1=[1,2,3,4,5];
        let arr2=[6,7,8,9];
        console.log(...arr1);//展开一个数组  
        console.log(...arr1,...arr2);  //连接一个数组
        // 展开运算符在函数中使用
        // reduce函数 
        // 累加和
        function sum(...numbers) {
            return numbers.reduce((preValue,currentValue)=>{
                return preValue+currentValue
            })
        }
        console.log(sum(1,2,3,4,5))
        let person={name:"tom",age:19};  //展开运算符不能展开对象
        let person2=person; //这里并不是对象的复制
        // 构造字面量对象时使用展开运算符
        let person3={...person};
        person.name="ab";
        console.log(person2);  //{name: 'ab', age: 19}
        console.log(person3);  //{name: 'tom', age: 19}
        // console.log(...person);

        // 在复制对象的时候 更改对象里面的属性
        // 属性的更改实际上是合并的操作
        let person4={...person,name:"jerry",address:"moon"};
        console.log(person4);  //{name: 'jerry', age: 19, address: 'moon'}
    </script>

函数式组件使用props

因为函数可以传递参数,所以可将props传进函数中,(state和refs不可以,因为没有this)

普通函数:由于没有对象的或者实例的调用,所以this指向js顶级对象window

    <script type="text/babel">
        function Person (props){
        	console.log(this)  //undefined
            const {name,age,sex}=props;
            return (
                    <ul>
                        <li>name:{name}</li>
                        <li>age:{age+1}</li>
                        <li>sex:{sex}</li>
                    </ul>
                )
        }
        // 将对组件标签的限制放在 函数的外部
        Person.propTypes={
            name:PropTypes.string.isRequired,
            age:PropTypes.number,
            sex:PropTypes.string,
            speak:PropTypes.func,
            }
        Person.defaultProps={
                name:'Seven',
                sex:'女'
            }

        ReactDOM.render(<Person age={20} sex="女" />,document.querySelector('.test'))
    </script>

总结

  1. 每个组件的对象都会有props(properties的简写)属性
  2. 组件标签中的所有属性都保存在props中
  3. 通过标签属性从组件内传递变化的数据
  4. 注意:组件内部不要修改props数据
  5. 使用prop-types库进行限制(需要引入prop-type库)
  6. 内部读取某个属性值 this.props.name
  7. 扩展属性:将对象的所有属性通过prop传递 <Person {...p}>
  8. 默认的属性值 Person.defaultProps={age:19}
  9. 组件类的构造函数 constructor(props){super(props);console.log(props)//打印所有属性}

组件实例的三大核心属性3:refs

字符串形式的ref使用方法(因为效率问题,逐渐被淘汰):

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    <div class="test">

    </div>
    <script src="./js/react.development.js"></script>
    <script src="./js/react-dom.development.js"></script>
    <script src="./js/babel.min.js"></script>
    <!-- 引入prop-types,用于对组件标签属性进行限制 -->
    <script src="./js/prop-types.js"></script>
    <script type="text/babel">
         class Demo extends React.Component{
             showDate1=()=>{
                //  注意这里是refs
                 const {input1}=this.refs
                 alert(input1.value)
             }
             showDate2=()=>{
                 const {input2}=this.refs
                 alert(input2.value)
             }

             render(){
                 return(
                     <div>
                        <input  ref="input1" type="text" placeholder="点击按钮提示数据"/>&nbsp;
                        <button  onClick={this.showDate1}>点击提示左侧数据</button>&nbsp;
                        <input ref="input2" onBlur={this.showDate2} type="text"  placeholder="失去焦点提示数据"/>&nbsp;
                    </div>
                 )
             }
         }
        //  渲染组件到页面
        ReactDOM.render(<Demo/>,document.querySelector('.test'))
    </script>
</body>
</html>

回调式的ref:

内联式(使用较多)

ref能够自动调用函数 并且将当前节点作为实参传递给函数

只需将当前节点赋值给实例自身

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>

<body>
    <div class="test">

    </div>
    <script src="./js/react.development.js"></script>
    <script src="./js/react-dom.development.js"></script>
    <script src="./js/babel.min.js"></script>
    <!-- 引入prop-types,用于对组件标签属性进行限制 -->
    <script src="./js/prop-types.js"></script>
    <script type="text/babel">
        class Demo extends React.Component{
            state={isHot:true}
            changeWeather=()=>{
                const {isHot}=this.state;
                this.setState({isHot:!isHot})
            }
             showDate1=()=>{
                 const {input}=this
                 alert(input.value)
             }
             render(){
                 const {isHot}=this.state;
                 return(
                     <div>
                        <h2>今天天气很{isHot?'炎热':'凉爽'}</h2>
                        <input  ref={currentNode=>{this.input=currentNode;console.log("@",currentNode);}}  type="text" placeholder="点击按钮提示数据"/>&nbsp;
                        <button  onClick={this.showDate1}>点击提示左侧数据</button>
                        <button  onClick={this.changeWeather}>点击我切换天气</button>
                    </div>
                 )
             }
         }
        //  渲染组件到页面
        ReactDOM.render(<Demo/>,document.querySelector('.test'))
    </script>
</body>

</html>

由于再更新(state发生变化)过程中会点函数会被执行两次,第一次传入参数null(用于清除更新之前的函数操作)第二次传入参数DOM元素。因为每次渲染时会创建一个新的函数实例,清空旧的并且设置新的。

class绑定组件式ref:

    <script type="text/babel">
        class Demo extends React.Component{
            state={isHot:true}
            changeWeather=()=>{
                const {isHot}=this.state;
                this.setState({isHot:!isHot})
            }
             showDate1=()=>{
                 const {input}=this
                 alert(input.value)
             }
             saveInput=(c)=>{
                 this.input=c;
                 console.log('@',c);
             }
             render(){
                 const {isHot}=this.state;
                 return(
                     <div>
                        <h2>今天天气很{isHot?'炎热':'凉爽'}</h2>
                        {/*<input  ref={currentNode=>{this.input1=currentNode;console.log("@",currentNode);}}  type="text" placeholder="点击按钮提示数据"/>&nbsp;*/}
                        <input ref={this.saveInput} type="text"/>
                        <button  onClick={this.showDate1}>点击提示左侧数据</button>
                        <button  onClick={this.changeWeather}>点击我切换天气</button>
                    </div>
                 )
             }
         }
        //  渲染组件到页面
        ReactDOM.render(<Demo/>,document.querySelector('.test'))
    </script>

最新的createRef:

    <script type="text/babel">
        class Demo extends React.Component{
            /*
            React.createRef调用 后可以返回一个容器,该容器可以存储被ref所标识的节点,但是该容器是”专人专用“
            */
            myRef=React.createRef();
             showDate1=()=>{
                 console.log(this.myRef.current.value);
             }
             render(){
                 return(
                     <div>
                        <input ref={this.myRef} type="text"/>
                        <button  onClick={this.showDate1}>点击提示左侧数据</button>
                    </div>
                 )
             }
         }
        //  渲染组件到页面
        ReactDOM.render(<Demo/>,document.querySelector('.test'))
    </script>