React学习(二)----- 面向组件编程

1、React开发工具安装

步骤:谷歌浏览器右上角三个点 ----- 更多工具 ----- 扩展程序 ----- 打开右上角的开发者模式 ----- 页面左上角的首页图标 ----- 下方打开Chrome网上应用店 ----- 搜索React,找到 facebook 出版的开发工具添加

但是浏览器一般无法打开Chrome应用商店,下方提供百度云链接,阅读者下载直接导入即可,导入方式:

步骤:谷歌浏览器右上角三个点 ----- 更多工具 ----- 扩展程序 ----- 打开右上角的开发者模式 ----- 点击加载已解压的扩展程序 ----- 选择下载好的文件夹导入即可 ----- 点击浏览器右上角的图标 ----- 将 React 插件右方的钉子点亮(编写 React 程序时将自动亮起)

地址:链接:https://pan.baidu.com/s/1FGfk2LNNusAYewHsZwlO4w   提取码:hmi1

2、创建组件的两种形式

  • 函数式组件
    <!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>函数式组件</title>
    </head>
    <body>
      <!-- 容器 -->
      <div id="box"></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">
        // 创建函数式组件
        // 注意:1>调用者:react   2>this指向:undefined,因为script脚本需要babel翻译,翻译后使用了严格模式,而严格
        // 模式不允许自定义函数中的this指向window
        function Demo(){
          console.log(this)//undefined
          return <h2>我是用函数定义的组件(适用于【简单组件】的定义)</h2>
        }
        // 将组件渲染到页面上
        ReactDOM.render(<Demo />,document.getElementById("box"))
      </script>
    </body>
    </html>
    View Code

    /*
    执行完ReactDOM.render(<Demo />,document.getElementById("box"))之后发生了什么???
    1、React解析组件标签,找到Demo组件;
    2、发现组件是使用函数定义的,随后调用该函数,将返回的虚拟Dom转换成真实的Dom,随后呈现在页面中;
    */

           注意:函数式组件玩儿不了state和refs,只能玩儿一下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 id="box"></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,用于对组件的标签属性进行限制 ,引入全局对象PropTypes-->
  <script src="../js/prop-types.js"></script>

  <script type="text/babel">
    // 1、创建组件
    function Demo(props){
      console.log(props)
      const {name,age,sex} = props 
      return (
          <ul>
            <li>姓名:{name}</li>
            <li>性别:{sex}</li>
            <li>年龄:{age + 1}</li>
          </ul>
        )
    }
    Demo.propTypes = {
      name:PropTypes.string.isRequired,
      age:PropTypes.number.isRequired,
      sex:PropTypes.string
    }
    Demo.defaultProps = {
      sex:'人...'
    }
    // 2、将组件渲染到页面上
    const obj = {name:"jerry", age:22}
    ReactDOM.render(<Demo {...obj}/>,document.getElementById("box"))
  </script>
</body>
</html>
View Code
  • 类式组件
    • class基础知识

1、构造器 constructor() 不是必须写的,要对实例做一些初始化的操作,如添加指定属性时才写,其中的this是指类的实例对象,constructor()  从创建到销毁,只执行一次

2、如果A类继承了B类时,且A类中写了构造器,那A类的构造器中super函数必须放在第一行调用;

3、类中定义的方法都是放在了类的原型对象上,供实例去使用;

    • 例子:
      <!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 id="box"></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">
          // 1、创建类式组件
          class MyComponent extends React.Component{
            render(){
              return <h2>我是用类定义的组件(适用于【复杂组件】的定义)</h2>
            }
          } 
          console.log(new MyComponent())
          // 2、将组件渲染到页面上
          ReactDOM.render(<MyComponent />,document.getElementById("box"))
        </script>
      </body>
      </html>
      View Code

      render:必须要有一个返回值,返回值是jsx语法,其实也是一个虚拟dom;

      1、render 是放在哪里的???----- 类的原型对象上,供实例使用
      2、实例是谁创建的???----- React内部会创建组件实例对象,调用render()得到虚拟DOM, 并解析为真实DOM
      3、render 函数中的this是谁??? ----- MyComponent类(组件)的实例对象
      4、render 函数调用几次???----- 1+n(1是初始化的那次,n是状态更新的次数)
          /*
            执行完ReactDOM.render(<MyComponent />,document.getElementById("box"))之后发生了什么???
            1、React解析组件标签,找到MyComponent组件;
            2、发现组件是使用类定义的,随后new出来该类的实例,并通过该实例调用到原型上的render方法,
               将返回的虚拟Dom转换成真实的Dom,随后呈现在页面中;
            */
  • 复杂组件(有状态)和简单组件(无状态)的区分??? 
    • 组件三大核心属性一:state
      • 示例
        <script type="text/babel">
            // 1、创建一个类式组件
            class Weather extends React.Component{
              // 定义初始状态
              constructor(props){
                super(props);
                // state初始值为null,低版本为一个空对象{}
                this.state = {
                  isHot : true
                }
              }
              // 定义虚拟dom
              render(){
                const {isHot} = this.state
                return (
                  <h2>今天天气很{isHot ? '炎热' : '寒冷'}</h2>
                )
              }
            }
        
            // 2、将组件渲染到页面上
            ReactDOM.render(<Weather />,document.getElementById("box"))
          </script>
        View Code
      • 事件绑定修改state
        • 类中定义方法中的this
          class Person {
                constructor(name){
                  this.name = 'wxh'
                }
                speak(){
                  /*
                    speak放在哪里??? 在类Person的原型上,供实例使用
                    当 Person 的实例调用 speak 时,speak 里面的this是指 Person 实例
                   */
                  console.log(this)
                  console.log(`My name is ${this.name}`)
                }
              }
              const p1 = new Person();
              p1.speak()//Person {name: "wxh"}  My name is wxh
              const x = p1.speak;
              /*
                this 为什么是undefined,而不是window???----- 因为 class 中定义的方法,内部自动开启了严格模式 'use strict'
               */
              console.log(x())//报错: Cannot read property 'name' of undefined
        • 示例:
          <script type="text/babel">
              // 1、创建一个类式组件
              class Weather extends React.Component{
                // 定义初始状态
                constructor(props){
                  super(props);
                  // state初始值为null,低版本为一个空对象{}
                  this.state = {
                    isHot : true
                  }
                }
                // 定义虚拟dom
                render(){
                  const {isHot} = this.state
                  return (
                    /*
                       事件处理:
                       1、React 事件的命名采用小驼峰式(camelCase),而不是纯小写
                     */
                    <h2 onClick={this.handlerClick}>今天天气很{isHot ? '炎热' : '寒冷'}</h2>
                  )
                }
                handlerClick(){
                  /*
                    1、handlerClick放在哪里??? 在类Weather的原型上,供实例使用
                    2、当 Weather 的实例调用 handlerClick 时,handlerClick 的this是指 Weather 实例
                    3、this为什么是undefined???-----由于 handlerClick 是作为 onClick 的回调,所以不是通过实例调用的,
                      是直接调用,且类中方法默认开启了局部的严格模式,所以是 undefined
                   */
                  console.log(this)
                }
              }
          
              // 2、将组件渲染到页面上
              ReactDOM.render(<Weather />,document.getElementById("box"))
            </script>

          现象:this为undefined,如何解决???

          /*
               1、强制绑定this: 通过函数对象的bind()返回一个this为实例对象的新函数
               所以点击事件执行时,先到实例自身的属性上去查找,若查找不到,再去类的原型对象上去查找
           */
            this.handlerClick = this.handlerClick.bind(this);

          二、自定义方法 ----- 赋值语句的形式+箭头函数(是定义在实例对象上)

          handlerClick= ()=>{this.setState({
                isHot:!this.state.isHot
             })
          }
        • 事件中state修改
          /*
             严重注意:
          1、状态 state 不可直接修改,要借助一个内置的 API:setState("对象(需要修改的值)","回调函数") 来进行更新,且更新是一种合并,不是替换;
          2、回调函数的作用:1>查看数据是否修改成功 2>在当前函数当中获取到最新的DOM结构,相当于nextTick
          3、这个函数是个异步的 同步先执行,在执行异步
          */ this.setState({ isHot:!this.state.isHot })
        • state的简写方式
          class Weather extends React.Component{
                // 初始化状态,直接定义在实例对象上
                state = {
                  isHot : true
                }
                // 定义虚拟dom
                render(){
                  const {isHot} = this.state
                  return (
                    <h2 onClick={this.handlerClick}>今天天气很{isHot ? '炎热' : '寒冷'}</h2>
                  )
                }
              }
    • 组件三大核心属性二:props
      • 示例(
        1. 每个组件对象都会有 props(properties的简写) 属性,默认为一个空对象{}
        2. 组件标签的所有属性都保存在props中
        3. props是只读的,不允许在组件内部修改,即this.props.name = 'xxx'

        <!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 id="box"></div>
          <div id="box1"></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">
            // 1、创建组件
            class Dad extends React.Component{
              render(){
                console.log(this)
                const {name,age,sex} = this.props
                return (
                  <ul>
                    <li>姓名:{name}</li>
                    <li>性别:{sex}</li>
                    <li>年龄:{age}</li>
                  </ul>
                )
              }
            }
            // 2、将组件渲染到页面上
            ReactDOM.render(<Dad name="wxh" age="18" sex="女"/>,document.getElementById("box"))
            ReactDOM.render(<Dad name="jerry" age="22" sex="男"/>,document.getElementById("box1"))
          </script>
        </body>
        </html>
        View Code
      • 批量传递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 id="box"></div>
            <div id="box1"></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">
              // 1、创建组件
              class Dad extends React.Component{
                render(){
                  console.log(this)
                  const {name,age,sex} = this.props
                  return (
                    <ul>
                      <li>姓名:{name}</li>
                      <li>性别:{sex}</li>
                      <li>年龄:{age}</li>
                    </ul>
                  )
                }
              }
              // 2、将组件渲染到页面上
              ReactDOM.render(<Dad name="wxh" age="18" sex="女"/>,document.getElementById("box"))
              const obj = {name:"jerry", age:"22", sex:"男"}
              ReactDOM.render(<Dad {...obj}/>,document.getElementById("box1"))
              // ReactDOM.render(<Dad name="jerry" age="22" sex="男"/>,document.getElementById("box1"))
            </script>
          </body>
          </html>
          View Code

          注意:

          let arr = [1,3,5,7,9]
          console.log(arr,...arr)//展开一个数组

           let arr1 = [1,3,5,7,9]
           let arr2 = [2,4,6,8,10]
           // 连接数组,相当于arr1展开 +一个逗号 + arr2展开
           console.log(...arr1)
           console.log([...arr1])
           console.log([...arr1,...arr2])

          // 在函数中使用:接收不定个数的形参
          function sum(...args){
             console.log(args)//[1,2,3,4]
             console.log(...args)//1 2 3 4
             return args.reduce((pre,cur)=>{
               return pre + cur
             })
          }
          console.log(sum(1,2,3,4))

          const obj = {name:"jerry", age:"22", sex:"男"}
          console.log(...obj)//报错,展开运算符不能展开一个对象

          const obj = {name:"jerry", age:"22", sex:"男",children:{school:'hhh'}}
          // console.log(...obj)//报错,展开运算符不能展开一个对象
          //新语法:字面量的方式复制一个对象,类似于object.assign(),一维属性为深拷贝,二维及以上为浅拷贝
          let cloneObj = {...obj}
          obj.name='wxh'
          obj.children.school='高一'
          console.log(obj,cloneObj)

          const obj = {name:"jerry", age:"22", sex:"男",children:{school:'hhh'}}
          console.log({...obj,name:'wxh',address:'地球'})//更新或者合并属性

          注意!!!原生JS中{...obj}是一种语法,而React中使用{...obj}和原生JS并不一样,是在差值表达式中使用了...obj,虽然这种写法在原生JS中是不允许的,但是在React+babel的共同处理下,支持这种语法!!!!! 

      • 对props进行限制
        console.log('@@@',...obj);//不允许随便使用,只允许在标签中使用,打印为空
        ReactDOM.render(<Dad {...obj}/>,document.getElementById("box1"))
        • 组件内部读取某个值:
           const {name,age,sex} = this.props
        • 对props中的属性值进行类型限制和必要性限制
          <!-- 引入prop-types,用于对组件的标签属性进行限制 ,引入全局对象PropTypes  v15.5以上-->
          <script src="../js/prop-types.js"></script>
          
          Dad.propTypes = {
            name:PropTypes.string.isRequired
          }
        • 默认属性值
          Dad.defaultProps = {
            sex:'人...'
          }
      • props的简写方式,赋值语句是给实例自身添加属性,而static+赋值语句是给类本身添加属性
        <!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 id="box"></div>
          <div id="box1"></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,用于对组件的标签属性进行限制 ,引入全局对象PropTypes-->
          <script src="../js/prop-types.js"></script>
        
          <script type="text/babel">
            // 1、创建组件
            class Dad extends React.Component{
              static propTypes = {
                name:PropTypes.string.isRequired,
                age:PropTypes.number.isRequired,
                sex:PropTypes.string
              }
              static defaultProps = {
                sex:'人...'
              }
              render(){
                const {name,age,sex} = this.props
                return (
                  <ul>
                    <li>姓名:{name}</li>
                    <li>性别:{sex}</li>
                    <li>年龄:{age + 1}</li>
                  </ul>
                )
              }
             
            }
            console.log(PropTypes)
            // 2、将组件渲染到页面上
            const obj = {name:"jerry", age:22, sex:"男"}
            ReactDOM.render(<Dad {...obj}/>,document.getElementById("box"))
            ReactDOM.render(<Dad name="wxh" age={18} />,document.getElementById("box1"))
          </script>
        </body>
        </html>
        View Code
    • 组件三大核心属性三:refs(

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

      • 字符串形式的ref(不建议使用) ----- 存在一些问题:https://github.com/facebook/react/pull/8333#issuecomment-271648615  官网也没有给出一个明确的解释,只是说会存在一些效率方面的问题,而且它已过时并可能会在未来的版本中被移除
        <!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 id="box"></div>
        
            <!-- 引入React的核心库 -->
            <script src="../js/react.development.js"></script>
            <!-- 引入React的扩展库,用来渲染虚拟DOM -->
            <script src="../js/react-dom.development.js"></script>
            <!-- 引入babel,用来将jsx转换为浏览器可以识别的文件 -->
            <script src="../js/babel.min.js"></script>
            <!-- 引入propTypes,对标签属性的类型、必要性以及默认值进行控制 -->
            <script src="../js/prop-types.js"></script>
        
            <script type="text/babel">
                // 1、创建组件
                class MyComponent extends React.Component{
                    // 对标签属性的类型、必要性进行控制
                    static propTypes = {
        
                    }
                    // 对标签属性的默认值进行控制
                    static defaultProps = {
        
                    }
                    // 初始化数据
                    state = {
        
                    }
                    render(){
                        return(
                            <div>
                                <input type="text" placeholder="点击按钮提示数据" ref="leftInput"/>&nbsp;
                                <button id="btn" onClick={this.handlerClick}>点我提示左侧的数据</button>&nbsp;
                                <input type="text" placeholder="失去焦点提取数据" onBlur={this.handlerBlur} ref="rightInput"/>
                            </div>
                        )
                    }
                    // 展示左侧输入框的数据  字符串形式
                    handlerClick = ()=>{
                        console.log(this.refs.leftInput)
                        let TDOM = this.refs.leftInput;
                        console.log(TDOM.value)
                    }
                    // 失去焦点显示数据  字符串形式
                    handlerBlur = ()=>{
                        const {rightInput} = this.refs;
                        console.log(rightInput.value)
                    }
                }
                // 2、将组件渲染到页面上
                ReactDOM.render(<MyComponent />,document.getElementById("box"))
            </script>
        </body>
        </html>
        View Code
      • 回调形式的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 id="box"></div>
        
            <!-- 引入React的核心库 -->
            <script src="../js/react.development.js"></script>
            <!-- 引入React的扩展库,用来渲染虚拟DOM -->
            <script src="../js/react-dom.development.js"></script>
            <!-- 引入babel,用来将jsx转换为浏览器可以识别的文件 -->
            <script src="../js/babel.min.js"></script>
            <!-- 引入propTypes,对标签属性的类型、必要性以及默认值进行控制 -->
            <script src="../js/prop-types.js"></script>
        
            <script type="text/babel">
                // 1、创建组件
                class MyComponent extends React.Component{
                    // 对标签属性的类型、必要性进行控制
                    static propTypes = {
        
                    }
                    // 对标签属性的默认值进行控制
                    static defaultProps = {
        
                    }
                    // 初始化数据
                    state = {
                      
                    }
                    render(){
                        return(
                            <div>
                            <input type="text" placeholder="点击按钮提示数据" ref={(currentNode)=>{this.leftInput = currentNode; console.log('@',currentNode)}}/>&nbsp; 
                            <br /><br />
                                <button id="btn" onClick={this.handlerClick}>点我提示左侧的数据</button>&nbsp;
                                <br /><br />
                                <input type="text" placeholder="失去焦点提取数据" onBlur={this.handlerBlur} ref={currentNode => this.rightInput = currentNode} />
                            </div>
                        )
                    }
                    // 展示左侧输入框的数据  字符串形式
                    handlerClick = ()=>{
                        const {leftInput} = this
                        console.log(leftInput.value)
                    }
                    // 失去焦点显示数据  字符串形式
                    handlerBlur = ()=>{
                        const {rightInput} = this;
                        console.log(rightInput.value)
                    }
                }
                // 2、将组件渲染到页面上
                ReactDOM.render(<MyComponent />,document.getElementById("box"))
            </script>
        </body>
        </html>
        View 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>
        </head>
        <body>
            <!-- 容器 -->
            <div id="box"></div>
        
            <!-- 引入React的核心库 -->
            <script src="../js/react.development.js"></script>
            <!-- 引入React的扩展库,用来渲染虚拟DOM -->
            <script src="../js/react-dom.development.js"></script>
            <!-- 引入babel,用来将jsx转换为浏览器可以识别的文件 -->
            <script src="../js/babel.min.js"></script>
            <!-- 引入propTypes,对标签属性的类型、必要性以及默认值进行控制 -->
            <script src="../js/prop-types.js"></script>
        
            <script type="text/babel">
                // 1、创建组件
                class MyComponent extends React.Component{
                    // 对标签属性的类型、必要性进行控制
                    static propTypes = {
        
                    }
                    // 对标签属性的默认值进行控制
                    static defaultProps = {
        
                    }
                    // 初始化数据
                    state = {
                        isHot : true
                    }
                    render(){
                        const {isHot} = this.state
                        return(
                            <div>
                                <h2 onClick = {this.changeState}>今天天气好{isHot ? '晴朗' : '凉爽'}</h2>
                            {/*<input type="text" placeholder="点击按钮提示数据" ref={(currentNode)=>{this.leftInput = currentNode; console.log('@',currentNode)}}/>&nbsp;*/}
                            <input type="text" placeholder="点击按钮提示数据" ref={this.saveInputRef}/>&nbsp;    
                            <br /><br />
                                <button id="btn" onClick={this.handlerClick}>点我提示左侧的数据</button>&nbsp;
                                <br /><br />
                                <input type="text" placeholder="失去焦点提取数据" onBlur={this.handlerBlur} ref={currentNode => this.rightInput = currentNode} />
                            </div>
                        )
                    }
                    // 解决更新时执行两次的问题
                    saveInputRef = (currentNode)=>{
                        this.leftInput = currentNode; 
                        console.log('@',currentNode)
                    }
                    // 修改标识
                    changeState = () =>{
                        this.setState({
                            isHot : !this.state.isHot
                        })
                    }
                    // 展示左侧输入框的数据  字符串形式
                    handlerClick = ()=>{
                        const {leftInput} = this
                        console.log(leftInput.value)
                    }
                    // 失去焦点显示数据  字符串形式
                    handlerBlur = ()=>{
                        const {rightInput} = this;
                        console.log(rightInput.value)
                    }
                }
                // 2、将组件渲染到页面上
                ReactDOM.render(<MyComponent />,document.getElementById("box"))
            </script>
        </body>
        </html>
        View Code
        注意:回调 ref 中调用次数的问题??? ----- 调用者:React 
        
        如果 ref 回调函数是以内联函数的方式定义的,在更新(render调用)过程中它会被执行两次,第一次传入参数 null,然后第二次会传入参数 DOM 元素。这是因为在每次渲染时会创建一个新的函数实例,
        所以 React 清空旧的 ref 并且设置新的。通过将 ref 的回调函数定义成 class 的绑定函数的方式可以避免上述问题,但是大多数情况下它是无关紧要的。
      •  createRef创建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 id="box"></div>
        
            <!-- 引入React的核心库 -->
            <script src="../js/react.development.js"></script>
            <!-- 引入React的扩展库,用来渲染虚拟DOM -->
            <script src="../js/react-dom.development.js"></script>
            <!-- 引入babel,用来将jsx转换为浏览器可以识别的文件 -->
            <script src="../js/babel.min.js"></script>
            <!-- 引入propTypes,对标签属性的类型、必要性以及默认值进行控制 -->
            <script src="../js/prop-types.js"></script>
        
            <script type="text/babel">
                // 1、创建组件
                class MyComponent extends React.Component{
                    // 对标签属性的类型、必要性进行控制
                    static propTypes = {
        
                    }
                    // 对标签属性的默认值进行控制
                    static defaultProps = {
        
                    }
                    // 初始化数据
                    state = {
        
                    }
                    /*
                      React.createRef 调用后可以返回一个容器,该容器可以存储被 ref 所标识的节点,该容器是“专人专用”,只能存一个
                     */
                    myRef = React.createRef() 
                    render(){
                        console.log(this)
                        return(
                            <div>
                                <input type="text" ref={this.myRef} placeholder="失去焦点提取数据" onBlur={this.handlerBlur}/>
                            </div>
                        )
                    }
                    // 失去焦点显示数据  字符串形式
                    handlerBlur = ()=>{
                        const {current} = this.myRef;
                        console.log(current.value)
                    }
                }
                // 2、将组件渲染到页面上
                ReactDOM.render(<MyComponent />,document.getElementById("box"))
            </script>
        </body>
        </html>
        View Code

        注意:

        React.createRef 调用后可以返回一个容器,该容器可以存储被 ref 所标识的节点,该容器是“专人专用”,只能存一个

3、React中的事件处理

  •  示例
           render(){
                    return(
                        <div>
                            <input type="text" placeholder="失去焦点提取数据" onBlur={this.handlerBlur} ref={currentNode => this.rightInput = currentNode} />
                        </div>
                    )
                }
                /*
                  1.通过onXxx属性指定事件处理函数(注意大小写)
                    1)React使用的是自定义(合成)事件, 而不是使用的原生DOM事件    -----    为了更好的兼容性
                    2)React中的事件是通过事件委托方式处理的(委托给组件最外层的元素)    -----    为了更高效
                  2.通过event.target得到发生事件的DOM元素对象    -----    不要过度使用ref
                */
                // 失去焦点显示数据  字符串形式
                handlerBlur = (e)=>{
                    console.log(e.target)
                    console.log(e.target.value)
                }
    View Code
    /*
      1.通过onXxx属性指定事件处理函数(注意大小写)
         1)React使用的是自定义(合成)事件, 而不是使用的原生DOM事件    -----    为了更好的兼容性
         2)React中的事件是通过事件委托方式处理的(委托给组件最外层的元素)    -----    为了更高效
      2.通过event.target得到发生事件的DOM元素对象    -----    不要过度使用ref
    */

4、收集表单数据(包含表单的组件分类)

  • 非受控组件:表单中所有输入类 DOM 的值,现用现取,即点击按钮的时候才收集
    • Ref的形式
      <!--
       * @Descripttion: 
       * @version: 
       * @Author: 北栀女孩儿
       * @Date: 2021-08-30 09:28:15
       * @LastEditTime: 2021-08-30 09:52:22
      -->
      <!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 id="box"></div>
      
          <!-- 引入React的核心库 -->
          <script src="../js/react.development.js"></script>
          <!-- 引入React的扩展库,用来渲染虚拟DOM -->
          <script src="../js/react-dom.development.js"></script>
          <!-- 引入babel,用来将jsx转换为浏览器可以识别的文件 -->
          <script src="../js/babel.min.js"></script>
          <!-- 引入propTypes,对标签属性的类型、必要性以及默认值进行控制 -->
          <script src="../js/prop-types.js"></script>
      
          <script type="text/babel">
              // 1、创建组件
              class MyComponent extends React.Component{
                  // 对标签属性的类型、必要性进行控制
                  static propTypes = {
      
                  }
                  // 对标签属性的默认值进行控制
                  static defaultProps = {
      
                  }
                  // 初始化数据action="http://www.atguigu.com"
                  state = {
                      
                  }
                  render(){
                      return(
                          <div>
                              <form  method="post" onSubmit={this.handlerSubmit}>
                                <label htmlFor="userName">用户名:</label> 
                                <input type="text" id="userName" name="userName" ref={currentNode => this.userName = currentNode}/>
                                <br />
                                <br />
                                <label htmlFor="password">密码:</label> 
                                <input type="password" id="password" name="password" ref={currentNode => this.password = currentNode}/> 
                                <br />
                                <br />
                                <button>提交</button>
                              </form>
                          </div>
                      )
                  }
                  // 处理提交的按钮
                  handlerSubmit = (e) =>{
                    // 阻止表单提交
                    e.preventDefault()
                    const {userName,password} = this;
                    alert(`你输入的用户名是:${userName.value},密码是${password.value}`)
                  }
              }
              // 2、将组件渲染到页面上
              ReactDOM.render(<MyComponent />,document.getElementById("box"))
          </script>
      </body>
      </html>
      View Code
  • 受控组件(推荐使用):表单中所有输入类 DOM 的值,随着输入将值维护到状态state中,即vue中的数据双向数据绑定
    <!--
     * @Descripttion: 
     * @version: 
     * @Author: 北栀女孩儿
     * @Date: 2021-08-30 09:28:15
     * @LastEditTime: 2021-08-30 10:09:48
    -->
    <!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 id="box"></div>
    
        <!-- 引入React的核心库 -->
        <script src="../js/react.development.js"></script>
        <!-- 引入React的扩展库,用来渲染虚拟DOM -->
        <script src="../js/react-dom.development.js"></script>
        <!-- 引入babel,用来将jsx转换为浏览器可以识别的文件 -->
        <script src="../js/babel.min.js"></script>
        <!-- 引入propTypes,对标签属性的类型、必要性以及默认值进行控制 -->
        <script src="../js/prop-types.js"></script>
    
        <script type="text/babel">
            // 1、创建组件
            class MyComponent extends React.Component{
                // 对标签属性的类型、必要性进行控制
                static propTypes = {
    
                }
                // 对标签属性的默认值进行控制
                static defaultProps = {
    
                }
                // 初始化数据
                state = {
                    userName :'',
                    password : ''
                }
                render(){
                    return(
                        <div>
                            <form action="" method="get">
                              <label htmlFor="userName">用户名:</label> 
                              <input type="text" id="userName" name="userName" onChange={this.handlerUserName}/>
                              <br />
                              <br />
                              <label htmlFor="password">密码:</label> 
                              <input type="password" id="password" name="password" onChange={this.handlerPassword}/> 
                              <br />
                              <br />
                              <button onClick={this.handlerSubmit}>提交</button>
                            </form>
                        </div>
                    )
                }
                // 监听 input 的输入事件 ,保存输入值到状态中
                handlerUserName = (e) => {
                  console.log(e.target.value)
                  this.setState({
                    userName : e.target.value
                  })
                }
                handlerPassword = (e) =>{
                  console.log(e.target.value)
                  this.setState({
                    password : e.target.value
                  })
                }
                // 处理提交的按钮
                handlerSubmit = (e) =>{
                  e.preventDefault()
                  const {userName,password} = this.state
                  alert(`你输入的用户名是:${userName},密码是${password}`)
                }
            }
            // 2、将组件渲染到页面上
            ReactDOM.render(<MyComponent />,document.getElementById("box"))
        </script>
    </body>
    </html>
    View Code
  • 扩展:高阶函数和函数的柯里化
    • 传参:错误的方式
      <label htmlFor="userName">用户名:</label> 
      // 这么写的含义是将  this.saveFormData函数的返回值  作为onChange事件的回调函数,即把 undefined 作为回调,input 输入值发生变化时不在执行!!!
      // 而不是将  this.saveFormData函数  作为回调
      <input type="text" id="userName" name="userName" onChange={this.saveFormData('userName')}/>
      
      
      // 监听 input 的输入事件 ,保存输入值到状态中
      saveFormData = (e) => {
        console.log(e.target.value)
      }
    • 正确的方式:高阶函数的方式
      <label htmlFor="userName">用户名:</label> 
      <input type="text" id="userName" name="userName" onChange={this.saveFormData('userName')}/>
      
      
      // 监听 input 的输入事件 ,保存输入值到状态中
      saveFormData = (dataType) => {
         // 返回的函数将是真正的 onChange 事件的回调函数
         return (event) => {
             console.log(dataType,event.target.value)
             this.setState({
                [dataType] : event.target.value
             })
             // 错误的方式:dataType这个时候是一个字符串,相当于'dataType',属性为dataType,而不是变量
             // this.setState({
             //   dataType : event.target.value
             // })
         }
      }

       高阶函数:如果一个函数符合下面2个规范中的任何一个,那该函数就是高阶函数

             1)若A函数,接收的参数是一个函数,那么A就可以称之为高阶函数;

             2)若A函数,调用的返回值依然是一个函数,那么A就可以称之为高阶函数;

              常见的高阶函数:Promise、定时器、一些数组方法(map、filter)等

      函数的柯里化:通过函数调用继续返回函数的方式,实现多次接收参数最后统一处理的函数编码形式

function sum(a){
  return (b) => {
    return (c) => {
      return a+b+c
    }
  }
}
console.log(sum(
1)(2)(3))//6
    • 正确的方式:非高阶函数的方式
      <label htmlFor="userName">用户名:</label> 
      <input type="text" id="userName" name="userName" onChange={(event)=>{this.saveFormData('userName',event.target.value)}}/>
      
       // 监听 input 的输入事件 ,保存输入值到状态中
       saveFormData = (dataType, value) => {
           console.log(dataType, value)
           this.setState({
               [dataType] : value
           })
       }

5、遇到的问题

       后续补充                                             

北栀女孩儿
原文地址:https://www.cnblogs.com/wxh0929/p/15179290.html