React componentization

Modularization and Componentization

Modular

  • A module is a js program provided externally 特定功能, generally a js file is a module
  • When the js of the application is written in modules, the application is a modular application

Componentization

  • 局部功能效果A component is a collection of code and resources used to implement (html/css/js/image, etc.)
  • When an application is implemented in a multi-component manner, the application is a componentized application

React defines components

functional components

Components are written in the form of functions, and the return value of the function is a DOM structure.

<!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>
    <style>
        .header{
      
      
            background-color: orange;
        }
    </style>
</head>
<body>
    <!-- 容器 -->
    <div id="test"></div>

    <!-- REACT ,react核心库-->
    <script type="text/javascript" src="../js/react.development.js"></script>
    <!-- REACTDOM ,支持react操作dom-->
    <script type="text/javascript" src="../js/react-dom.development.js"></script>
    <!-- 将jsx转换成js文件 -->
    <script type="text/javascript" src="../js/babel.min.js"></script>
    <!--text/babel表明是jsx  -->
    <script type="text/babel">
        // 1.创建函数式组件
        function Demo(){
      
      
            console.log(this)//注意this是undefined,因为babel翻译后开启了严格模式,严格模式下自定义的this是不允许指向window的
            return <h2>我是函数式组件(适用于【简单组件】的定义)</h2>
        }
        // 2.渲染虚拟DOM到页面
        // 如果渲染的是组件需要使用标签,并且首字母要大写,并且需要进行闭合
        ReactDOM.render(<Demo/>,document.getElementById("test"))
    </script> 


        <!-- 总结:
                执行了ReactDOM.render(<Demo/>.......之后,发生了什么?
                     1.React解析组件标签,找到了Demo组件。
                     2.发现组件是使用函数定义的,随后调用该函数,将返回的虚拟DOM转为真实DOM,随后呈现在页面中。 -->
</body>
</html>

class component

class supplement

  • The attributes of the class are stored on the instance object, and the methods on the class are stored on the prototype object of the class.
  • The methods in the class enable local strict mode by default, and this is undefined
<!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>
    <script>
        class Person {
      
      
            // 属性放在了类的实例对象上
            sex = 'f';
            constructor(name, age) {
      
      
                // this指向的是实例对象
                this.name = name
                this.age = age
            }

            // 方法放在了类的原型对象上,供实例使用 
            speak() {
      
      
                // 通过person实例调用speck时,this是对应的实例对象
                console.log(`我叫${ 
        this.name}, 我今年 ${ 
        this.age}岁了`);
            }
        }
        const p1 = new Person('yang', 20)
        const p2 = new Person('cheng', 21)
        
        console.log('p1:', p1);
        console.log('p2:', p2);

        p1.speak()
        p2.speak()
    </script>    
</body>
</html>

Output:
insert image description here
If a constructor is used in a subclass, it must be called usingsuper()

class component

  • The defined class needs to inherit React.Component
  • must write render
  • render must have a return value
  • After writing several component tags, several new component instances will be created
    eg:
<!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>
    <style>
        .header{
      
      
            background-color: orange;
        }
    </style>
</head>
<body>
    <!-- 容器 -->
    <div id="test"></div>

    <!-- REACT ,react核心库-->
    <script type="text/javascript" src="../js/react.development.js"></script>
    <!-- REACTDOM ,支持react操作dom-->
    <script type="text/javascript" src="../js/react-dom.development.js"></script>
    <!-- 将jsx转换成js文件 -->
    <script type="text/javascript" src="../js/babel.min.js"></script>
    <!--text/babel表明是jsx  -->
    <script type="text/babel">
        // 1.创建类式组件(需要继承React.Component;必须写render;render必须有返回值)
        class Demo extends React.Component{
      
      
            // render放在Demo的原型对象上,供实例使用
            // render中的this是谁?—Demo的实例对象,即Demo的组件实例对象。
            render(){
      
      
                return  <h2>我是类式组件(适用于【复杂组件】的定义)</h2>
            }
        }
        // 2.渲染虚拟DOM到页面()
        // Demo实例由React创建
        ReactDOM.render(<Demo/>,document.getElementById("test"))

    </script> 


        <!-- 总结:
                执行了ReactDOM.render(<Demo/>.......之后,发生了什么?
                    1.React解析组件标签,找到了Demo组件。
                    2.发现组件是使用类定义的,随后new出来该类的实例,并通过该实例调用到原型上的render方法。
                    3.将render返回的虚拟DOM转为真实DOM,随后呈现在页面中。 -->
</body>
</html>

Output component instance object in render

render(){
    
    
    console.log('组件实例对象', this);
          return  <h2>我是类式组件(适用于【复杂组件】的定义)</h2>
      }

insert image description here

Simple and complex components

  • Components with state are called complex components
  • The state is stored in the state of the component instance object (a component defined using a class),
    so a component with a state property is a complex component.

Three properties of components

The three major properties of components actually refer to the three major properties of component instances, and only class components can have instances, so the three major properties of components are actually for class components

There are three types of component instance objectsAttributesstate、props、refs

state

State is generally used to store the value of some variables. We know that the state attribute is on the component instance object. If you want to get the value in the state, you need to get the component instance object, and this in the class constructor is the component instance object , so we can 类的构造函数implement the operation on the state through.

The constructor has parameters, you can refer to the official documentation to use props as parameters

  constructor(props) {
    
    
    super(props);
    this.state = {
    
     seconds: 0 };
  }

The state data can be obtained by passing in the constructor or render this.state.seconds(make sure this is the component instance object)

Supplement: event binding of react

Format: click eventonClick={clickEvent}

  • Events use camelCase
  • There is no need to add () after the method name
  • The method name is wrapped with {}

eg:

        // 1.创建类式组件
        class Weather extends React.Component{
    
    
            render(){
    
    
                // 原生的事件绑定<h1 οnclick="clickEvent()">
                // {}中放的是js表达式,如果函数加()就会自动执行,onClick的值就是一个undefined
                return <h1 onClick={
    
    clickEvent}>今天天气真{
    
    this.state.isHot?"炎热":"凉爽"}</h1>
            }
        }
        // 2.渲染虚拟DOM到页面
        ReactDOM.render(<Weather/>,document.getElementById('test'))
        function clickEvent(){
    
    
            console.log('被点击了');
        }

state use cases

Achievement effect: click to switch the weather
insert image description here
insert image description here

  • The acquisition problem of this
<!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>
    <style>
        .header{
      
      
            background-color: orange;
        }
    </style>
</head>
<body>
    <!-- 容器 -->
    <div id="test"></div>

    <!-- REACT ,react核心库-->
    <script type="text/javascript" src="../js/react.development.js"></script>
    <!-- REACTDOM ,支持react操作dom-->
    <script type="text/javascript" src="../js/react-dom.development.js"></script>
    <!-- 将jsx转换成js文件 -->
    <script type="text/javascript" src="../js/babel.min.js"></script>
    <!--text/babel表明是jsx  -->
    <script type="text/babel">
        // 1.创建类式组件
        class Weather extends React.Component{
      
      
            constructor(props){
      
      
                super(props)
                // 组件实例对象上存储值(写成对象)
                this.state = {
      
      
                    isHot:false
                }

                // 利用bind修改changeWeather的this并且将返回的新函数赋值给定义的changeWeather2(bind返回一个新的函数)
                // changeWeather2是在实例对象上的
                this.changeWeather2 = this.changeWeather.bind(this)

            }
            render(){
      
      
                return <h1 onClick={
      
      this.changeWeather2}>今天天气真{
      
      this.state.isHot?"炎热":"凉爽"}</h1>
            }
            changeWeather(){
      
      
                // 类的方法放在类的原型对象上,所以changeWeather放在Weather的原型对象上
                // 所以如果通过Weather的实例对象调用changeWeather时,changeWeather的实例对象就是Weather的实例对象
                // 由于类中的方法默认开启严格模式,所以如果是直接调用函数(即不使用实例对象调用)那么this就是undefine
                // 按<h1 onClick={this.changeWeather}>的写法,是将实例对象的方法赋值给onClick,所以如果点击后再调用的话就是直接调用,this就是undefined
                    // 并且类中的方法默认开启了局部严格模式,所以changeWeather中的this是undefined
                // 所以进行修改,在构造函数中进行设置this.changeWeather2 = this.changeWeather.bind(this)
                console.log(this);
            }

        }
        // 2.渲染虚拟DOM到页面
        ReactDOM.render(<Weather/>,document.getElementById('test'))

        // function changeWeather(){
      
      
        //     console.log('修改isHot')
        //     // babel开启严格模式,this指向是undefined,所以放在外面不可取,放在类中作为方法使用
        // }

    </script> 
</body>
</html>
  • Implement Responsive Data
<!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>
    <style>
        .header{
      
      
            background-color: orange;
        }
    </style>
</head>
<body>
    <!-- 容器 -->
    <div id="test"></div>

    <!-- REACT ,react核心库-->
    <script type="text/javascript" src="../js/react.development.js"></script>
    <!-- REACTDOM ,支持react操作dom-->
    <script type="text/javascript" src="../js/react-dom.development.js"></script>
    <!-- 将jsx转换成js文件 -->
    <script type="text/javascript" src="../js/babel.min.js"></script>
    <!--text/babel表明是jsx  -->
    <script type="text/babel">
        // 1.创建类式组件
        class Weather extends React.Component{
      
      
            constructor(props){
      
      
                super(props)
                // 组件实例对象上存储值(写成对象)
                this.state = {
      
      
                    isHot:false,
                    wind:'微风'
                }

                // 修改changeWeather的this并且赋值给定义的changeWeather(bind返回一个新的函数)
                // 这里定义的 this.changeWeather是在实例对象上的
                this.changeWeather = this.changeWeather.bind(this)

            }
            render(){
      
      
                return <h1 onClick={
      
      this.changeWeather}>今天天气真{
      
      this.state.isHot?"炎热":"凉爽"},{
      
      this.state.wind}</h1>
            }
            // 这里定义的 changeWeather是在类的原型对象上的
            changeWeather(){
      
      

                // 如果直接修改数据实现不了响应式数据
                // this.state.isHot = !this.state.isHot错误写法

                //  使用setState()才能实现数据的响应式,该方法是React.Component原型对象上的方法
                // setState()的参数是对象
                // setState()只是修改某个属性值, 不会修改其他属性值
                const isHot = this.state.isHot
                this.setState({
      
      isHot:!isHot})

            }

        }
        // 2.渲染虚拟DOM到页面
        ReactDOM.render(<Weather/>,document.getElementById('test'))

    </script> 
    <!-- setState总结:
        1.构造器调用1次
        2.render调用n+1次(n代表状态更新的次数,1是第一次渲染的时候进行调用)
        3.数据是进行修改,而不是覆盖 -->
</body>
</html>
  • Shorthand
<!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>
    <style>
        .header{
      
      
            background-color: orange;
        }
    </style>
</head>
<body>
    <!-- 容器 -->
    <div id="test"></div>

    <!-- REACT ,react核心库-->
    <script type="text/javascript" src="../js/react.development.js"></script>
    <!-- REACTDOM ,支持react操作dom-->
    <script type="text/javascript" src="../js/react-dom.development.js"></script>
    <!-- 将jsx转换成js文件 -->
    <script type="text/javascript" src="../js/babel.min.js"></script>
    <!--text/babel表明是jsx  -->
    <script type="text/babel">
        // 1.创建类式组件
        class Weather extends React.Component{
      
      
            // 可以将组件实例对象的属性直接在类中定义
            state = {
      
      
                    isHot:false,
                    wind:'微风'
                }
            render(){
      
      
                return <h1 onClick={
      
      this.changeWeather}>今天天气真{
      
      this.state.isHot?"炎热":"凉爽"},{
      
      this.state.wind}</h1>
            }
            // 直接将方法写成属性赋值的样式,那么方法就放在组件实例对象上了
            // 使用箭头函数,this就会向外找就是组件实例对象(结构上的向外查找,class中的this就是实例对象)
            changeWeather = ()=>{
      
      
                const isHot = this.state.isHot
                this.setState({
      
      isHot:!isHot})
            }

        }
        // 2.渲染虚拟DOM到页面
        ReactDOM.render(<Weather/>,document.getElementById('test'))

    </script> 
</body>
</html>
  • The methods in the component class are generally 绑定事件used and 赋值语句+箭头函数defined in the way to be used
  • The properties in the component class can be defined directly in the class

state summary

  • understand
  1. state is the most important attribute of the component object, and the value is an object (can contain multiple key-value combinations)
  2. The component is called a "state machine", and the corresponding page display is updated by updating the state of the component (re-rendering the component)
  • strong attention
  1. The this in the render method of the component is the component instance object
  2. This is undefined in the component custom method, how to solve it?
    a) Mandatory binding of this: through the bind() of the function object
    b) Arrow function----------recommended
  3. State data, 不能直接修改或更新,必须调用setState()
    call setState, react will update the data state and call it again render()to re-render the page and refresh the data.

props

Basic use of props

属性名=属性How to use props: prop is to pass the value for the passed value when the component is called , and then you can propsaccess the passed value in the component instance object.
eg:

<!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>
    <style>
        .header{
      
      
            background-color: orange;
        }
    </style>
</head>
<body>
    <!-- 容器 -->
    <div id="test"></div>
    <div id="test2"></div>
    <div id="test3"></div>

    <script type="text/javascript" src="../js/react.development.js"></script>
    <script type="text/javascript" src="../js/react-dom.development.js"></script>
    <script type="text/javascript" src="../js/babel.min.js"></script>
    <script type="text/babel">
        // 1.创建类式组件
        class Person extends React.Component{
      
      
            render(){
      
      
                return(
                    <ul>
                        <li>姓名:{
      
      this.props.name}</li>
                        <li>年龄:{
      
      this.props.age}</li>
                        <li>性别:{
      
      this.props.sex}</li>
                    </ul>
                )
            }
        }
        // 2.渲染虚拟DOM到页面
        ReactDOM.render(<Person name='yang' age='20' sex='nv'/>,document.getElementById('test'))
        ReactDOM.render(<Person name='zhe' age='21' sex='nan'/>,document.getElementById('test2'))
        ReactDOM.render(<Person name='ming' age='22' sex='nv'/>,document.getElementById('test3'))
    </script> 
</body>
</html>

insert image description here

Passing props in batches

When passing multiple props directly on the component will be a bit messy, so you can use the batch transfer method for value transfer.
Concatenative data transfer using the spread operator (…)

<!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>
    <style>
        .header{
      
      
            background-color: orange;
        }
    </style>
</head>
<body>
    <!-- 容器 -->
    <div id="test"></div>
    <div id="test2"></div>
    <div id="test3"></div>

    <script type="text/javascript" src="../js/react.development.js"></script>
    <script type="text/javascript" src="../js/react-dom.development.js"></script>
    <script type="text/javascript" src="../js/babel.min.js"></script>
    <script type="text/babel">
        // 1.创建类式组件
        class Person extends React.Component{
      
      
            render(){
      
      
                const{
      
      name,age,sex} = this.props
                return(
                    <ul>
                        <li>姓名:{
      
      name}</li>
                        <li>年龄:{
      
      age}</li>
                        <li>性别:{
      
      sex}</li>
                    </ul>
                )
            }
        }
        // 2.渲染虚拟DOM到页面
        const p = {
      
      name:'yang',age:20,sex:'nv'}
        // 注意扩展运算符...不能直接给对象使用(可以直接给数组使用),即在js中...p语法是不对的,但是可以这样使用{...p}(这里的{}表示的是对象, 浅克隆复制对象)
        // 但是在react+jsx中可以直接使用...p(注意这里的{}表示的是使用js表达式),但也仅限于标签传递属性时可以使用
        ReactDOM.render(<Person {
      
      ...p}/>,document.getElementById('test3'))

    </script> 
    <!-- 总结:
    1. props批量传递属性是通过{...p}实现的 -->
</body>
</html>

props limit

The attributes passed to the component generally have format restrictions on some special attributes. For example, they must be of string type, we can restrict them on the component, and react provides us with the propTypes attribute to restrict:

The prop-types dependency package needs to be introduced to have the PropTypes property.

// Person是一个组件名
        Person.propTypes={
    
    
            // 名字必须指定而且是字符串
            // 直接使用PropTypes需要引入prop-types依赖包(用于对组件标签属性进行限制)
            name: PropTypes.string.isRequired,
            sex: PropTypes.string,
            age: PropTypes.number,
            speak: PropTypes.func
        }

It is also possible to set default values ​​for properties

 // 属性默认值
        Person.defaultProps={
    
    
            sex:'男',
            age:18
        }

eg: case use

<!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>
    <style>
        .header{
      
      
            background-color: orange;
        }
    </style>
</head>
<body>
    <!-- 容器 -->
    <div id="test"></div>
    <div id="test2"></div>
    <div id="test3"></div>

    <script type="text/javascript" src="../js/react.development.js"></script>
    <script type="text/javascript" src="../js/react-dom.development.js"></script>
    <script type="text/javascript" src="../js/babel.min.js"></script>
    <!-- 引入propTypes用于对组件标签属性进行限制,引入该模块会有PropTypes属性 -->
    <script type="text/javascript" src="../js/prop-types.js"></script>
    <script type="text/babel">
        // 1.创建类式组件
        class Person extends React.Component{
      
      
            render(){
      
      
                const{
      
      name,age,sex} = this.props
                return(
                    <ul>
                        <li>姓名:{
      
      name}</li>
                        <li>年龄:{
      
      age+1}</li>
                        <li>性别:{
      
      sex}</li>
                    </ul>
                )
            }
        }
        // 对属性进行限制
        Person.propTypes={
      
      
            // 名字必须指定而且是字符串
            // 直接使用PropTypes需要引入prop-types依赖包(用于对组件标签属性进行限制)
            name: PropTypes.string.isRequired,
            sex: PropTypes.string,
            age: PropTypes.number,
            // 限制speak是一个函数
            speak: PropTypes.func
        }
        // 属性默认值
        Person.defaultProps={
      
      
            sex:'男',
            age:18
        }
        

        // 2.渲染虚拟DOM到页面
        ReactDOM.render(<Person name='yang' age={
      
      20} sex='nv' speak={
      
      speak}/>,document.getElementById('test'))
        ReactDOM.render(<Person name='zhe' age={
      
      21} sex='nan'/>,document.getElementById('test2'))

        const p = {
      
      name:'yang',age:20,sex:'nv'}
        ReactDOM.render(<Person {
      
      ...p}/>,document.getElementById('test3'))

        function speak(){
      
      
            console.log('说话:balabalabala');
        }

    </script> 
    <!-- 总结:
    1. props批量传递属性是通过{...p}实现的 -->
</body>
</html>

Note: props are read-only

Shorthand for props

propTypesBoth and defaultPropsare attributes added to the component. The essence of a class component is a class, so if you want to add attributes to a class component, you can directly use staticthe identifier in the class to add it.

So the above code can be written as the following code

<!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>
    <style>
        .header{
      
      
            background-color: orange;
        }
    </style>
</head>
<body>
    <!-- 容器 -->
    <div id="test"></div>
    <div id="test2"></div>
    <div id="test3"></div>

    <script type="text/javascript" src="../js/react.development.js"></script>
    <script type="text/javascript" src="../js/react-dom.development.js"></script>
    <script type="text/javascript" src="../js/babel.min.js"></script>
    <!-- 引入propTypes用于对组件标签书机型进行限制 -->
    <script type="text/javascript" src="../js/prop-types.js"></script>
    <script type="text/babel">
        // 1.创建类式组件
        class Person extends React.Component{
      
      
            render(){
      
      
                const{
      
      name,age,sex} = this.props
                return(
                    <ul>
                        <li>姓名:{
      
      name}</li>
                        <li>年龄:{
      
      age+1}</li>
                        <li>性别:{
      
      sex}</li>
                    </ul>
                )
            }
            // 对属性的限制可以直接利用static放在class上
            // 对属性进行限制
            static propTypes={
      
      
                // 名字必须指定而且是字符串
                name: PropTypes.string.isRequired,
                sex: PropTypes.string,
                age: PropTypes.number,
                speak: PropTypes.func
            }
            // 属性默认值
            static defaultProps={
      
      
                sex:'男',
                age:18
            }
        }
        
        // 2.渲染虚拟DOM到页面
        ReactDOM.render(<Person name='yang' age={
      
      20} sex='nv' speak={
      
      speak}/>,document.getElementById('test'))
        ReactDOM.render(<Person name='zhe' age={
      
      21} sex='nan'/>,document.getElementById('test2'))

        const p = {
      
      name:'yang',age:20,sex:'nv'}
        // 注意扩展运算符...不能直接给对象使用,即在js中...p语法是不对的,但是可以这样使用{...p}
        // 但是在react+jsx中可以直接使用...p(注意这里的{}表示的是使用js表达式)
        ReactDOM.render(<Person {
      
      ...p}/>,document.getElementById('test3'))

        function speak(){
      
      
            console.log('说话:balabalabala');
        }

    </script> 
    <!-- 总结:
    1. props是只读的
    2. 对props属性的限制可以直接利用static放在class上-->
</body>
</html>

The props parameter of the constructor in the class

When using constructors in classes before, we usually pass a props attribute. as follows:

constructor(props){
    
    
       super(props)
   }

A constructor in a class generally has two functions:

  • Initialize the internal state by assigning an object to this.state. —— You can define the state attribute directly in the class
  • Bind instances for event handlers. ——Can be defined directly in the class as an arrow function

Because the above two contents can be directly defined and solved in the class, it does not have to be executed in the arrow function, so the constructor of the class can generally be omitted.
If you write a constructor, you can pass parameters or not pass parameters (props), but if you write a constructor, you must write super. this.propsThe difference between passing props parameters and not passing props parameters is: if you do not pass props parameters, you cannot access props properties in the constructor .

Functional components use props

Different from the other two properties of the component instance, the component of the function can also use the props property, taking advantage of the feature that the function can pass parameters.
It's just that when you want to limit the parameters at this time, you can only limit them outside the function
eg:

<!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>
    <style>
        .header{
      
      
            background-color: orange;
        }
    </style>
</head>
<body>
    <!-- 容器 -->
    <div id="test"></div>
    <div id="test2"></div>
    <div id="test3"></div>

    <script type="text/javascript" src="../js/react.development.js"></script>
    <script type="text/javascript" src="../js/react-dom.development.js"></script>
    <script type="text/javascript" src="../js/babel.min.js"></script>
    <script type="text/javascript" src="../js/prop-types.js"></script>
    <script type="text/babel">
        // 1.创建函数式组件
        function Person(props){
      
      
            return(
                    <ul>
                        <li>姓名:{
      
      props.name}</li>
                        <li>年龄:{
      
      props.age}</li>
                        <li>性别:{
      
      props.sex}</li>
                    </ul>
                )
        }
        // 对属性进行限制
        Person.propTypes={
      
      
            // 名字必须指定而且是字符串
            name: PropTypes.string.isRequired,
            sex: PropTypes.string,
            age: PropTypes.number,
            speak: PropTypes.func
        }
        // 属性默认值
        Person.defaultProps={
      
      
            sex:'男',
            age:18
        }

        // 2.渲染虚拟DOM到页面
        ReactDOM.render(<Person name='yang' age={
      
      20} sex='nv'/>,document.getElementById('test'))
        ReactDOM.render(<Person name='zhe' age={
      
      21} sex='nan'/>,document.getElementById('test2'))
        ReactDOM.render(<Person name='ming' age={
      
      22} sex='nv'/>,document.getElementById('test3'))



    </script> 
    <!-- 总结:
    1. 函数式组件只能使用props,直接通过参数进行使用
    2. 也可以进行限制 -->
</body>
</html>

refs

You can use refa unique tag to represent the component. After the tag is identified, you can refsread the tag on the property of the component instance object.
eg:

string ref

When the label is identified by ref, it can be identified directly with a string.

case:

  1. Click the button, the pop-up window prompts the data
  2. Lost focus, pop-up window prompts data
<!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>字符串ref</title>
</head>
<body>
    <!-- 容器 -->
    <div id="test"></div>

    <script type="text/javascript" src="../js/react.development.js"></script>
    <script type="text/javascript" src="../js/react-dom.development.js"></script>
    <script type="text/javascript" src="../js/babel.min.js"></script>
    <script type="text/javascript" src="../js/prop-types.js"></script>

    <script type="text/babel">
        //  <!-- 1.创建类式组件 -->
        class Demo extends React.Component{
      
      
            render(){
      
      
                return (
                    <div>
                        <input ref="input1" type="text" id="input1" placeholder="点击按钮提示数据"/>
                        <button onClick={
      
      this.showDataClick}>点我提示左侧数据</button>&nbsp;
                        <input ref="input2" onBlur={
      
      this.showDataBlur} type="text" placeholder="失去焦点提示数据"/>
                    </div>
                )
            }
            showDataClick = ()=>{
      
      
            //读取ref标识的标签
                const {
      
      input1} = this.refs
                alert(input1.value)
            }
            showDataBlur = ()=>{
      
      
                const {
      
      input2} = this.refs
                alert(input2.value)
            }
        }

        // <!--2.渲染虚拟DOM到页面 -->
        ReactDOM.render(<Demo/>,document.getElementById('test'))
        
    </script>


<!-- 小结:
        1. ref用于标识存储dom元素
        2. 在组件实例对象的refs中总重可以获取对应的dom元素进行参送
    
    缺点:效率低-->
</body>
</html> 

Disadvantages of string ref: low efficiency

ref in the form of a callback function

When a tag uses ref identification, it needs to use a callback function for identification.
The callback function has one parameter, which is the label node where it is located.
The callback function is in the form of an arrow function, so this is determined by the upper level, and the upper level is a render()function, so this points to the component instance object, so you can directly put the parameter of the callback function (the node) on this, so in The node can be read directly on the component instance object.

<!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>字符串ref</title>
</head>
<body>
    <!-- 容器 -->
    <div id="test"></div>

    <script type="text/javascript" src="../js/react.development.js"></script>
    <script type="text/javascript" src="../js/react-dom.development.js"></script>
    <script type="text/javascript" src="../js/babel.min.js"></script>
    <script type="text/javascript" src="../js/prop-types.js"></script>

    <script type="text/babel">
        //  <!-- 1.创建类式组件 -->
        class Demo extends React.Component{
      
      
            showDataClick = ()=>{
      
      
                const {
      
      input1} = this
                alert(input1.value)
            }
            showDataBlur = ()=>{
      
      
                const {
      
      input2} = this
                alert(input2.value)
            }
            render(){
      
      
                return (
                    <div>
                        <input ref={
      
      (currentNode)=>{
      
      this.input1=currentNode}} type="text" id="input1" placeholder="点击按钮提示数据"/>
                        <button onClick={
      
      this.showDataClick}>点我提示左侧数据</button>&nbsp;
                        <input ref={
      
      (currentNode)=>{
      
      this.input2=currentNode}} onBlur={
      
      this.showDataBlur} type="text" placeholder="失去焦点提示数据"/>
                    </div>
                )
            }
        }

        // <!--2.渲染虚拟DOM到页面 -->
        ReactDOM.render(<Demo/>,document.getElementById('test'))
        
    </script>


<!-- 小结:
        ref={(currentNode)=>{this.input1=currentNode}}:将当前节点挂载到组件实例对象上
-->
</body>
</html> 

The ref of the callback function is more commonly used.

The problem of the number of callback executions of the callback ref
If ref 回调函数it is 内联函数defined (that is, the code defined in one line), 更新过程it will be executed in it 两次, and the parameters will be passed in for the first time null, and then the parameters will be passed in for the second time DOM 元素.
Note that the update process render()is re-executed rendering
eg:

<!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>字符串ref</title>
</head>
<body>
    <!-- 容器 -->
    <div id="test"></div>

    <script type="text/javascript" src="../js/react.development.js"></script>
    <script type="text/javascript" src="../js/react-dom.development.js"></script>
    <script type="text/javascript" src="../js/babel.min.js"></script>
    <script type="text/javascript" src="../js/prop-types.js"></script>

    <script type="text/babel">
        //  <!-- 1.创建类式组件 -->
        class Demo extends React.Component{
      
      
            state ={
      
      
                isHot:true
            }
            showDataClick = ()=>{
      
      
                const {
      
      input1} = this
                alert(input1.value)
            }
            changeWeather=()=>{
      
      
                const {
      
      isHot} = this.state
                this.setState({
      
      isHot : !isHot})
            }
            saveInput=(currentNode)=>{
      
      
                this.input1 = currentNode;
                console.log('@',currentNode);
            }
            render(){
      
      
                const {
      
      isHot} = this.state
                return (
                    <div>
                        <h1 onClick = {
      
      this.changeWeather}>今天天气很{
      
      isHot?'炎热':'凉爽'}</h1>
                        <input ref={
      
      (currentNode)=>{
      
      this.input1=currentNode ; console.log('@',currentNode);}} type="text" id="input1" placeholder="点击按钮提示数据"/> 
                        <button onClick={
      
      this.showDataClick}>点我提示左侧数据</button>
                    </div>
                )
            }
        }

        // <!--2.渲染虚拟DOM到页面 -->
        ReactDOM.render(<Demo/>,document.getElementById('test'))  
    </script>
</body>
</html> 

output:

insert image description here
This is because, when the data changes and re-calls render(), when the function defined by ref is read, because it is not sure whether the parameters of the previous call have been cleared, in order to ensure the cleanness of the parameters, ref will first pass in a null parameter , to ensure that the parameters are cleared, and then passed to the current node for execution, so the callback function that renders the ref again after the data is updated will be executed twice.
Therefore, in order to avoid this problem, the function can not be written as a callback function, but written as 类绑定的回调函数.
Right now:

<!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>字符串ref</title>
</head>
<body>
    <!-- 容器 -->
    <div id="test"></div>

    <script type="text/javascript" src="../js/react.development.js"></script>
    <script type="text/javascript" src="../js/react-dom.development.js"></script>
    <script type="text/javascript" src="../js/babel.min.js"></script>
    <script type="text/javascript" src="../js/prop-types.js"></script>

    <script type="text/babel">
        //  <!-- 1.创建类式组件 -->
        class Demo extends React.Component{
      
      
            state ={
      
      
                isHot:true
            }
            showDataClick = ()=>{
      
      
                const {
      
      input1} = this
                alert(input1.value)
            }
            changeWeather=()=>{
      
      
                const {
      
      isHot} = this.state
                this.setState({
      
      isHot : !isHot})
            }
            saveInput=(currentNode)=>{
      
      
                this.input1 = currentNode;
                console.log('@',currentNode);
            }
            render(){
      
      
                const {
      
      isHot} = this.state
                return (
                    <div>
                        <h1 onClick = {
      
      this.changeWeather}>今天天气很{
      
      isHot?'炎热':'凉爽'}</h1>
                        {
      
      /*<input ref={(currentNode)=>{this.input1=currentNode ; console.log('@',currentNode);}} type="text" id="input1" placeholder="点击按钮提示数据"/> */}
                        <input ref={
      
      this.saveInput} type="text" id="input1" placeholder="点击按钮提示数据"/>
                        <button onClick={
      
      this.showDataClick}>点我提示左侧数据</button>
                    </div>
                )
            }
        }

        // <!--2.渲染虚拟DOM到页面 -->
        ReactDOM.render(<Demo/>,document.getElementById('test'))  
    </script>
<!-- 小结:
        ref={(currentNode)=>{this.input1=currentNode}}:将当前节点挂载到组件实例对象上
        当使用内联的回调函数的ref,在第一次加载的时候会执行一次;当数据修改的时候diaoyongrender会执行两次,第一次是为了清空dom元素,第二次返回标记的ref
        通过将ref的回调函数定义成class的绑定函数可以解决此问题
-->
</body>
</html> 

createRef

React.createRefAfter the call, a container can be returned, which can store the node identified by ref. The container is "specially dedicated" (that is, a createRef can only store one dom element). After that, the container can be identified by ref in the label, then
the Tags are then stored in that container.
use:

<!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>字符串ref</title>
</head>
<body>
    <!-- 容器 -->
    <div id="test"></div>

    <script type="text/javascript" src="../js/react.development.js"></script>
    <script type="text/javascript" src="../js/react-dom.development.js"></script>
    <script type="text/javascript" src="../js/babel.min.js"></script>
    <script type="text/javascript" src="../js/prop-types.js"></script>

    <script type="text/babel">
        //  <!-- 1.创建类式组件 -->
        class Demo extends React.Component{
      
      
            // React.createRef调用后可以返回一个容器,该容器可以存储被ref所标识的节点,该容器是“专人专用”的(即一个createRef只能存储一个dom元素)
            myRef = React.createRef()
            myRef2 = React.createRef()
            showDataClick = ()=>{
      
      
                console.log(this.myRef);
                alert(this.myRef.current.value)
            }
            showDataBlur = ()=>{
      
      
                const {
      
      input2} = this
                alert(this.myRef2.current.value)
            }
            render(){
      
      
                return (
                    <div>
                        {
      
      /*this.myRef就会将该DOM元素放在上面创建的ref中*/}
                        <input ref={
      
      this.myRef} type="text" id="input1" placeholder="点击按钮提示数据"/>
                        <button onClick={
      
      this.showDataClick}>点我提示左侧数据</button>&nbsp;
                        <input ref={
      
      this.myRef2} onBlur={
      
      this.showDataBlur} type="text" placeholder="失去焦点提示数据"/>
                    </div>
                )
            }
        }

        // <!--2.渲染虚拟DOM到页面 -->
        ReactDOM.render(<Demo/>,document.getElementById('test'))
        
    </script>
<!-- 小结:
    myRef = React.createRef()
    React.createRef调用后可以返回一个容器,该容器可以存储被ref所标识的节点,该容器是“专人专川用”的(即一个createRef只能存储一个dom元素)
-->
</body>
</html> 

Guess you like

Origin blog.csdn.net/mantou_riji/article/details/127213995