React使用

目录

14.1、什么是React

14.2、如何使用React

14.2.1、React的基本使用

14.2.2、React JSX

14.2.3、模块与组件、模块化与组件化的理解

14.3、React面向组件编程

14.3.1、函数式组件:

14.3.2、类式组件

14.3.3、React 组合组件

14.4、组件三大核心属性之一 ---------State

14.4.1、React State 介绍

14.4.2、State的基本使用

14.4.3、改变天气状态案例

14.4.4、天气案例简写

14.5、组件三大核心属性二--------props

14.5.1、Props的基本介绍

14.5.2、Props应用

14.6、组件三大核心属性三-------refs与事件处理

14.6.1、ref介绍

14.6.2、ref使用

14.6.2.1字符串形式的Ref

14.6.2.2、回调函数形式的ref

14.6.2.3、创建React.createRef()

14.6.3、事件处理

14.6.3.1、React单击事件

14.6.3.2、React 阻止事件默认行为

14.6.3.3、 在事件处理方法中传递参数

14.6.3.4、 实战:开关按钮

14.7、React生命周期

14.8、React脚手架以及项目框架

14.8.1、关于React脚手架

14.8.2、React项目架构

14.9、React综合案例--------todolist


14.1、什么是React

React是一个用于构建用户界面的JavaScript库。简单来说就是用来构建web应用,它相当于MVC中的V,是Web应用程序的视图层,使用React可以将一些简短、独立的代码片段组成复杂的UI界面,这些代码片段被称作“组件”。是由Facebook开发的一个开源框架。

React 优势

React框架的设计初衷主要用于构建UI,而构建UI的核心思想就是封装组件。组件维护自身的状态和UI,每当状态发货所能改变时,就会自动重新渲染组件自身,而不需要反复查找DOM元素后再重新选渲染整个组件

  • 声明式
  • 基于组件
  • 高效灵活

14.2、如何使用React

React应用开发涉及的内容比较广泛,我们还是从最简单、最基本的“Hello React”开始学习。简单来讲就是如何将HTML的网页内容,以React框架渲染的方式来实现。

第一步,就是学习如何安装和使用React框架。React框架的安装和使用很简单,可以直接通过CDN方式获取React和ReactDOM的UMD版本引用,具体如下:

<script crossorigin src="https://unpkg.com/react@16/umd/react.production.js" />
<script crossorigin src="https://unpkg.com/react@16/umd/react.production.js" />

不过上述版本只能用于开发环境,不适合生产换将。React压缩和优化之后的生产换将版本链接如下:

<script crossorigin src="https://unpkg.com/react@16/umd/react.production.min.js" />
<script crossorigin src="https://unpkg.com/react-dom@16/umd/react-dom.production.min.js" />  

此外还要引入babel编译器所需的库文件

<!-- Don't use this in production : -->
<script src="https://unpkg.com/babel-standalone@6.15.0.babel.min.js"></script>

注意:Babel 库文件在生产环境下是不建议使用的

除了上述利用CDN引入这些库文件,也可以通过将这些库文件下载到本来后来引用也是可以的。

关于上面以CDN方式引入的一组库文件(react.js、react-dom.js、babel.js 这3个脚本文件),具体描述如下:

  • react.js 是React框架的核心库
  • react-dom.min.js 提供与DOM相关的功能。
  • babel.min.js 由Babel编译器提供,可以将ES6代码转为ES5代码,这样就能在不支持ES6的浏览器上执行React代码(请注意在生产环境下不建议使用)。

下面,就是开始第一个使用React框架实现“Hello React”应用的代码实例,具体如下:

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8">
    <title>Hello_React</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>
    
    
    <!-- 这里babel表示写的不是js而是jsx,依赖babel来完成 -->
    <script type="text/babel"> /*此处一定要写babel*/
    //1、创建虚拟Dom
    const VDOM = <h1>Hello,React</h1> /*此处一定不要写引号,因为不是字符串*/
    //2、渲染虚拟DOM到页面
    ReactDOM.render(VDOM,document.getElementById('test'))
    
    </script> 
  </body>
</html>

14.2.1、React的基本使用

React 框架的核心优势之一,就是支持创建虚拟DOM来提高页面性能。

虚拟DOM,这又是个什么东西呢?那实际DOM你总该知道吧,当设计人员在设计船传统的HTML网页时,会在页面中定义若干的DOM元素,这些DOM元素就是所谓的实际DOM。但是对于复杂的页面UI而言,往往会定义大量的实际DOM。频繁地操作大量实际DOM,往往会带来访问性能的严重下降,用户体验也会随之变差。为了避免这些问题,React框架专门针对这个现象引入了虚拟DOM机制,以避免频繁的DOM曹组带来的性能下降问题。

React DOM类似于一种将相关的实际DOM组合在一起的集合,是有区别于传统概念上的DOM元素的,如果将其理解为DOM组件应该更为贴切。因此,React框架将React DOM称为虚拟DOM。

使用React,DOM语法中的creatElement()方法,以虚拟DOM方式实现的代码实例,具体如下:

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8">
    <title>使用js创建虚拟DOM</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">
      //创建虚拟dom
      const VDOM = React.createElement('h1',{id:'title'},'hello,React!')
      ReactDOM.render(VDOM,document.getElementById('test'))
    </script>
  </body>
</html>

当然我们也可以使用JSX的语法来创建虚拟DOM

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8">
    <title>使用jsx创建虚拟DOM</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/babel">
    //创建虚拟Dom
    
    const VDOM = (
    <h1 id="title">
    <span>Hello,React!</span>    
      </h1>
      )
      
      //渲染虚拟DOM到页面
      ReactDOM.render(VDOM,document.getElementById('test'))
    </script>
    
  </body>
</html>

14.2.2、React JSX

看完上述内容,如何通过React DOM的createElement()和JSX语法两种方法创建虚拟DOM,并将创建的虚拟DOM渲染到页面中的过程。那什么是JSX呢?

所谓JSX其实就是JavaScript XML的缩写,直译过来就是基于JavaScript的XML。JSX看起来似乎是一种XML格式,其本质仍旧是一种JavaScript语言,只不过是将JavaScript脚本代码写成XML样式。

const h1 = (<h1>Hello,React!<h1>);

这就是使用JSX创建的一个虚拟DOM。

JSX的语法规则

  1. 定义DOM时,不要写引号
  2. 标签中混入JS表达式时要用{}
  3. 样式的类名指定不要用class,要用className。
  4. 内联样式,要用Style={{key:value}}的形式去写,并且比较复杂的属性要用小驼峰的方式书写,例如{{fontSize:‘20px’}}
  5. 虚拟DOM必须只有一个根标签
  6. 标签必须闭合
  7. 关于标签首字母
    1. 若小写字母开头,则将该标签转为html中同名元素,若HTML中无该标签对应的同名元素,则报错。
    2. 若大写字母开头,react就去渲染对应的组件,若组件没有定义,则报错。

【js语句(代码)】与【js表达式】的区别

  1. 表达式:一个表达式会产生一个值,可以放在任何一个需要值的地方,例如 下面这些都是表达式
    1. a;
    2. a+b;
    3. demo(1);
    4. arr.map() ;
    5. function test () { };可以const x = 这些js表达式,看是否可以输出 ,就可以判断是否为函数表达式
  1. 语句(代码)下面这些都是语句(代码)
    1. if ( ) { }
    2. for( ) { }
    3. switch ( ) {case: xxxxx}

14.2.3、模块与组件、模块化与组件化的理解

模块

向外提供特定功能的js程序,一般就是一个js文件

组件

用来实现局部功能效果的代码和资源的集合(html/css/js/image)

模块化

当应用的js都以模块来编写的,这个应用就是一个模块化的应用

组件化

当应用是以多组件的方式实现,这个应用就是一个组件化的应用

14.3、React面向组件编程

14.3.1、函数式组件:

在使用函数用来定义组件时,函数名称首字母一定要大写,在渲染到组件页面的时候,一定要写demo标签,并且必须是闭合标签(一定要符合jsx语法规则)

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8">
    <title>函数式组件</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/babel">
    //1.创建函数式组件  
    function Demo(){
    return <h2>我是用函数定义的组件(适用于【简单组件的定义】)</h2>
    }
    //2.渲染组件到页面
    ReactDOM.render(<Demo/>,document.getElementById('test'))
    </script>
  </body>
</html>

编译原理:

React解析了组件标签,找到了DOM组件,发现组件时使用函数定义的,随后调用该函数,将返回的虚拟DOM转为真实DOM,随后呈现在页面中。

14.3.2、类式组件

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8">
    <title>Document</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/babel">
    //1.创建类式组件
    //react中要求,如果你用类的形式去定义组件,要求你的类必须要继承一个类,这个类是React中内置的一个类
    class MyComponen extends React.Component{
    render(){
    return <h2>我是用类定义的组件(适用于【复杂组件的定义】)</h2>
    }     
    } 
    //2.渲染组件到页面
    ReactDOM.render(<MyComponen/>,document.getElementById('test'))
    </script>
  </body>
</html>

编译原理:

React解析组件标签,找到了MyComponent组件,发现组件是使用类定义的,随后new出来该类的实例,并通过该实例调用到原型上的render方法,将render返回的虚拟DOm转为真实DOM,随后呈现在页面中。

总结

  • 函数式组件,函数的名称就是组件的名称,同样类式组件,类名就是组件名
  • 简单组件与复杂组件

如果你的组件是有状态的,那么这个组件就是复杂组件,没有状态就是简单组件

14.3.3、React 组合组件

React组件支持在自身定义中引用其他组件,从而构成React组合组件(也称复合组件)。使用React组合组件定义的好处就是,可以使用同一组件来抽象出任意层次的细节,比如一个React表单组件就可以由多个不同类型的子组件来构成。

下面通过React组合组件来实现用户登录表单的代码实例

<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <title>组合组件</title>
</head>
<body>
    <div id="test"></div>

    <script src="https://unpkg.com/react@16/umd/react.development.js"></script>
    <script src="https://unpkg.com/react-dom@16/umd/react-dom.development.js"> </script> 
    <script src="https://unpkg.com/babel-standalone@6.15.0/babel.min.js"></script>

    <script type="text/babel">
        var divReact = document.getElementById('test');
        function FormTitle() {
            return <h4>User Login</h4>
        }
        function UserId() {
            const userId = (
                <p>User Id(*) : <input type="text"/> </p>
            );
            return userId;
        }

        function UserName() {
            const userName = (
                <p>User Name : <input type = "text"/></p>
            );
            return userName;
        }
        function Password() { 
            const password = (
                <p>Password(*) : <input type = "text"/></p>
            );
            return password;
        }
        function Submit() { 
            const submit = (
                <p><button>Login</button></p>
            );
            return submit;
        }
        function FormLogin() {
            return (
                <div id="aaa">
                    <FormTitle/>
                    <UserId/>
                    <UserName/>
                    <Password/>
                    <Submit/>
                </div>
            );
        }
        ReactDOM.render(<FormLogin/>,divReact);
    </script>
</body>
</html>

14.4、组件三大核心属性之一 ---------State

14.4.1、React State 介绍

React将组件看成一个状态机(State Machines),通过其内部定义的状态与生命周期实现与用户界面的交互,维持组件的不同状态。

在React框架中定义了一个状态(State)概念,并通过状态(State)来实现React组件的状态机特性。所谓React组件的“状态机”特性,就是指组件通过与用户的交互,实现不同的状态,然后通过渲染UI保证用户界面和数据的一致性。

简单来说,React中很多地方需要用到数据,这在React 中被叫做状态,我们需要一个专门管理状态的方法,于是State就诞生了。state被要求有两个基本功能,一、能够存储一定的值,从而能被React使用,二、能够在它改变的时候可以被React监听到并且重新渲染。

举个例子:

14.4.2、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">
    <script src="https://unpkg.com/react@16/umd/react.development.js"></script>
    <script src="https://unpkg.com/react-dom@16/umd/react-dom.development.js"> </script> 
    <script src="https://unpkg.com/babel-standalone@6.15.0/babel.min.js"></script>

    <title>state的基本使用</title>
</head>
<body>
    <div id="test"></div>
    <script type="text/babel">
        class Demo extends React.Component {
            constructor(props){
                super(props);
                    this.state = {name:'Jack'};
            }
            render() {
                return <h2>{this.state.name}</h2>
            };
        }
        ReactDOM.render(<Demo/>,document.getElementById('test'))
    </script>
</body>
</html>
  • 在React 组件类内部,要定义constructor()构造方法(17行代码),以及render()方法(见21~23行代码)
  • 然后通过“this.state”来使用React状态(见22行代码)

React状态(State)的初始化工作如何实现呢?

  • 19行代码中,就是“this.state”的初始化方式。可以定义若干组属性名,属性值

最后将Props参数添加到构造方法中

  • 在17行代码中,在constructor()构造方法中定义props参数
  • 18行代码,通过super关键字调用props参数,实现对父类构造函数的引用

通过上面几个基本步骤,就实现了React State的定义与使用,当然在实际应用中是很灵活的,需要多加练习才可以慢慢掌握。

14.4.3、改变天气状态案例

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Document</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/babel"> 
      //1.创建组件
      class Wether extends React.Component{
          //构造器调用几次?-------1次
          constructor(props){
             super(props)  
             //初始化状态
             this.state = {isHot:true,wind:'大风'}
             //解决changeWeather中this指向问题
             this.demo = this.changeWeather.bind(this)
             /*
             bind可以做两件事
             1.可以生成一个新的函数
             2.可以修改函数中的this
             */
            }

            //render调用几次?----------1+n次  1是初始化的那次  n是状态更新的次数
          render(){
              //读取状态
              const {isHot} = this.state  //ES6解构赋值
              return <h1 id="title1" onClick={this.demo}>今天的天气很{isHot ? '炎热' : '凉爽'},现在的风级是{this.state.wind}</h1>
              //三元表达式:(boolean)? (true) :(fasle)
          }
           /*第三种添加点击事件的方法*/
            changeWeather(){
                //changeWeather放在了哪里?-------weather 的原型对象上供实例使用
                //由于changeWeather是作为onCLick的回调,所以不是通过实例调用的,是直接调用
                //类中的方法默认开启了局部的严格模式所以changeWeather中的this为underfined
            
                //获取原来的isHot值
                const isHot = this.state.isHot
                //严重注意:状态必须通过setState进行更新,且更新是一种合并,不是直接替换。
                this.setState({isHot:!isHot})
                //严重注意:状态不可以直接更改,下面这行就是直接更改!要借助一个内置的API去更改
                // this.state.isHot = !isHot   这是错误的写法

            }
      }  
     
      //2.渲染组件到页面
      ReactDOM.render(<Wether/>,document.getElementById('test'))


     /** 第一种添加点击事件的方法
      * const title1 = document.getElementById('title1')
      title1.addEventListener('click',()=>{
          //函数体
          console.log("标题被点击了");
      })*/

      /*第二种添加点击事件的方法
      const title1= document.getElementById('test')
      title1.onclick=()=>{
        console.log("标题被点击了");
      }*/
    </script>
</body>
</html>

14.4.4、天气案例简写

<!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="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/babel">
        class Weather extends React.Component{
            //初始化状态
            state = {isHot:false,wind:'微风'}

            render(){
                const {isHot} = this.state
                return <h1 onClick={this.changeWeather}>今天的天气很{isHot ? '炎热':'凉爽'},{this.state.wind}</h1>
            }
            
            //自定义方法————要用赋值语句的形式+箭头函数
            changeWeather = ()=>{
                const isHot = this.state.isHot
                this.setState({isHot:!isHot})
            }
        }

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

强烈注意

  1. 组件中的render方法中的this为组件实例对象
  2. 组件自定义方法中的this为underfind,如何解决

a、强制绑定this:通过函数对象的bind() 

this.changeWeather = this.changeWeather.bind(this)

b、箭头函数 

changeWeather = ()=>{
     const isHot = this.state.isHot
     this.setState({isHot:!isHot})
 }
  1. 状态数据,不能直接修改或更新 
this.setState({isHot:!isHot})

14.5、组件三大核心属性二--------props

上面我们知道React函数组件可以通过JavaScript函数方式实现,那么React函数组件就可以通过接受参数的传入。React框架定义了一个Props的概念,专门永爱实现React函数组件接受参数的输入.

14.5.1、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">
    <script src="https://unpkg.com/react@16/umd/react.development.js"></script>
    <script src="https://unpkg.com/react-dom@16/umd/react-dom.development.js"> </script> 
    <script src="https://unpkg.com/babel-standalone@6.15.0/babel.min.js"></script>

    <title>Document</title>
</head>
<body>
    <div id="test"></div>
    <script type="text/babel">
        function PropsReactComp(props){
            if(props){
                return <p> Hello,this is a React Props usage by {props.name}.</p>
            }else{
                return <p>Hello,this is a React Props introduction.</p>
            }
        }
        const eleProps = <PropsReactComp name = "Lucy"/>;
        ReactDOM.render(eleProps,document.getElementById('test'))
    </script>
</body>
</html>

代码说明:

  • 第16~22行代码分别定义了一个React函数组件(PropsReactComp()),注意在函数内定义了一个参数(props),具体说明如下:
    • 第17~21行代码通过条件语句判断参数(props)是否为“true”,若为true则执行第18行代码,若为false则执行第20行代码。
    • 在第18行代码中,通过参数(props)对象获取其“name”属性值,这个“name”属性的定义在下面的第23行代码中。
  • 在第23行代码中,通过const关键字定义了一个常量( eleProps ), 赋值为React函数组件()。这里的特别之处 在于,在React函数组件()中增加定义了一 个“name”属性,同时初始化了属性值("Lucy")。在前面的第18 行代码中,就是通过参数(props)对象获取了该“name”属性的 值。

页面展示效果如下:

14.5.2、Props应用

上面了解了props的基本操作,那么在实际开发中props的作用是什么呢?

Props是properties的简写,可以被定义为一种数据从组件传递到组件的方式,基本上就是父组件传递到子组件。将一个数据从一个React组件传递到另一个组件,主要是因为不想让组件渲染静态数据,而是将动态数据传递给组件。这也正是React的props发挥其作用的地方。

具体怎么使用呢?

有以下几种

1、只读

props在传递数据的过程中,是只读的不能修改的。
       

class App extends React.Component {
    // 第一步:给节点设置属性 `theme`
    render() {
        return <Toolbar theme="dark" />;
    }
}

function Toolbar(props) {
    // 第二步:子节点可以访问父节点的props属性,但只能读取不能修改
    return (
        <div>
            <ThemedButton theme={props.theme} />
        </div>
    );
}

class ThemedButton extends React.Component {
    // 第三步:孙子节点依然可访问props属性,同样只能读不能修改 
    render() {
        return <Button theme={this.props.theme} />;
    }
}

       

2、扩展属性

将对象的所有属性通过props传递

var props = { x: 1, y: 1, z:1 };
<Component {...props} />

// 上面等价于下面的写法
<Component x=1 y=1 z=1 />

3、默认属性值

//指定默认标签属性 
Person.defaultProps = { 
  sex:'男', //sex默认值为男 
  age:18 //age默认值为18 
}

4、props.children

<Welcome>Hello world!</Welcome>

function Welcome(props) {
    return <p>{props.children}</p>;
}

对于class组件,请使用this.props.children来获取:

class Welcome extends React.Component {
    render() {
        return <p>{this.props.children}</p>;
    }
}

下面我们使用类式组件组合使用一下

<!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="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">
        //创建组件
        class Person extends React.Component{
            //构造器是否接受props,是否传递给super,取决于:是否希望在构造器中通过this访问props
            constructor(props){
                // console.log(props);
                super(props)
                console.log('constructor',this.props);
            }
            //对标签属性进行类别、必要性的限制
            static propTypes={
              name:PropTypes.string.isRequired, //限制name必传,且为字符串
              sex:PropTypes.string, //限制sex为字符串
              age:PropTypes.number,//限制age为数值
              speak:PropTypes.func,//限制speak为函数
             }
            //指定默认标签属性
            static defaultProps={
              sex:'男', //sex默认值为男
              age:18    //age默认值为18
            }

              render(){
                  console.log(this);
                  const{name,age,sex} = this.props
                  return(
                    <ul>
                        <li>姓名:{name}</li>
                        <li>性別:{age+1}</li>   
                        <li>年齡:{sex}</li>
                    </ul>
                  )
              }
          } 
        
          //渲染組件到頁面
          ReactDOM.render(<Person name='tom'/>,document.getElementById('test')) //age里面只有写成这种形式,才可以是number的形式
         
    </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 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">
        //创建组件
          function Person(props){
              console.log(props);
              const{name,age,sex}=props
            return(
                    <ul>
                        <li>姓名:{name}</li>
                        <li>性別:{age}</li>   
                        <li>年齡:{sex}</li>
                    </ul>
                  )
          }

           //对标签属性进行类别、必要性的限制
           Person.propTypes={
              name:PropTypes.string.isRequired, //限制name必传,且为字符串
              sex:PropTypes.string, //限制sex为字符串
              age:PropTypes.number,//限制age为数值
              speak:PropTypes.func,//限制speak为函数
             }
            //指定默认标签属性
            Person.defaultProps={
              sex:'男', //sex默认值为男
              age:18    //age默认值为18
            }
          //渲染組件到頁面
          ReactDOM.render(<Person name='tom' />,document.getElementById('test')) //age里面只有写成这种形式,才可以是number的形式
         
    </script>
</body>

</html>

总结props与state的区别

  • props是组件对外的接口,state是组件对内的接口
  • State是可变的,是一组用于反映组件UI变化的状态集合
  • props对于使用它的组件来说,是只读的,要想修改props,只能通过该组件的父组件修改。

14.6、组件三大核心属性三-------refs与事件处理

14.6.1、ref介绍

ref是React提供的用来操控React组件实例或者DOM元素的接口;回调函数就是在DOM节点或组件上挂载函数,函数的入参是DOM节点或组件实例,达到的效果与字符串形式是一样的,都是获取其引用。

eact提供的这个ref属性,表示为对组件真正实例的引用,其实就是ReactDOM.render()返回的组件实例;需要区分一下,ReactDOM.render()渲染组件时返回的是组件实例;而渲染dom元素时,返回是具体的dom节点。

14.6.2、ref使用

14.6.2.1字符串形式的Ref

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Document</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/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="点击按钮提示数据"/>
                        <button onClick={this.showData}>点我提示左侧的数据</button>
                        <input ref="input2"onBlur = {this.showData2}type="text" placeholder="失去焦点提示数据"/>
                    </div>
                )
            }
        }

    //渲染组件到页面
    ReactDOM.render(<Demo/>,document.getElementById('test'))
    </script>
</body>
</html>

但是这种方式已经过时,建议不被使用

14.6.2.2、回调函数形式的ref

当组件安装时,React将使用DOM元素调用ref回调,并在卸载时调用null;

在componentDidMount或componentDidUpdate触发之前,Refs保证是最新的.(生命周期后续章节详细介绍)

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Document</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/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={c => this.input1=c} type="text" placeholder="点击按钮提示数据"/>
                        <button onClick={this.showData}>点我提示左侧的数据</button>
                        <input ref={c => this.input2=c} onBlur = {this.showData2}type="text" placeholder="失去焦点提示数据"/>
                    </div>
                )
            }
        }

    //渲染组件到页面
    ReactDOM.render(<Demo/>,document.getElementById('test'))
    </script>
</body>
</html>

14.6.2.3、创建React.createRef()

Refs是使用属性创建的,React.createRef()并通过ref属性附加到React元素。在构造组件时,通常将Refs分配给实例属性,以便可以在整个组件中引用它们

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Document</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/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="点击按钮提示数据"/>
                        <button onClick={this.showData}>点我提示左侧的数据</button>
                        <input onBlur={this.showData2} ref={this.myRef2} type="text" placeholder="失去焦点提示数据"/>
                    </div>
                )
            }
        }

    //渲染组件到页面
    ReactDOM.render(<Demo/>,document.getElementById('test'))
    </script>
</body>
</html>

14.6.3、事件处理

在React框架中,React元素的事件处理和JavaScript对HTML DOM元素处理的方式类似。但是,二者在语法上略有不同,根据官方文档的说明描述如下:

  • React事件绑定属性的命名采用驼峰式写法,而不是小写。
  • 如果采用JSX语法,则需要传入一个函数作为事件处理函数,而不是一个字符串(DOM元素的写法)。

那么,对于上面的两条规定如何理解呢?下面,我们通过对比 HTML DOM事件语法和React事件语法的书写方法,具体解释一下这两 条规定。

比如最常见的按钮(<button>)鼠标单击事件(Click),在HTMLDOM事件语法中需要写成如下格式:

<button οnclick="btn_click()">
	Click Me!
</button>

在使用React框架来实现时,应该这样写:

<button onClick = {btn_click}>
	Click Me!
</button>
  • onClick是鼠标单击事件名称,注意事件名称是采用小驼峰(注意 小驼峰写法和大驼峰写法的区别)写法的。
  • on_btn_click是鼠标单击事件的函数方法,注意是采用JSX方式 ({ })将函数方法包括进去的,而且不带小括号。

14.6.3.1、React单击事件

<!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">
    <script src="https://unpkg.com/react@16/umd/react.development.js"></script>
    <script src="https://unpkg.com/react-dom@16/umd/react-dom.development.js"> </script> 
    <script src="https://unpkg.com/babel-standalone@6.15.0/babel.min.js"></script>

    <title>React单击事件</title>
</head>
<body>
    <div id="test"></div>
    <script type="text/babel">
        function onBtnClick(){
            console.log("Clicked OK!");
        }
        const reactSpan= (
            <span>
                <h3>Hello React!</h3>
                <button onClick={onBtnClick}>Click</button>
            </span>
        )
        ReactDOM.render(reactSpan,document.getElementById('test'))
    </script>
</body>
</html>

14.6.3.2、React 阻止事件默认行为

<!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">
    <script src="https://unpkg.com/react@16/umd/react.development.js"></script>
    <script src="https://unpkg.com/react-dom@16/umd/react-dom.development.js"> </script> 
    <script src="https://unpkg.com/babel-standalone@6.15.0/babel.min.js"></script>

    <title>Document</title>
</head>
<body>
    <div id="test"></div>
    <script type="text/babel">
         function PreventLink() {
             function handleClick(){
                 e.preventDefault();
                 console.log("这个链接被点击了");
             }
             return(
                 <a href="https://reactjs.org" onClick={handleClick}>
                    Click 
                </a>
             );
         }
         const reactSpan = (
             <h3><PreventLink/></h3>
         )
        ReactDOM.render(reactSpan,document.getElementById('test'))
    </script>
</body>
</html>

我们可以看到点击链接是没有任何反应的, 而浏览器控制台中输出了第19行代码定义的 日志信息,说明preventDefault()方法成功阻止了超链接单击事件的默认 行为。

14.6.3.3、 在事件处理方法中传递参数

React事件处理应该也可以像JavaScript程序那样,在事件处理方法 中通过传递参数实现更复杂的功能。实际情况也确实如此,React可以 通过两种方式在事件处理方法中传递参数,分别是箭头函数方式和通过 bind()方法的绑定方式。

首先,我们看一下通过箭头函数传递参数的方法,请看下面的代码 实例:

<!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">
    <script src="https://unpkg.com/react@16/umd/react.development.js"></script>
    <script src="https://unpkg.com/react-dom@16/umd/react-dom.development.js"> </script> 
    <script src="https://unpkg.com/babel-standalone@6.15.0/babel.min.js"></script>

    <title>Document</title>
</head>
<body>
    <div id="test"></div>
    <script type="text/babel">
        class Demo extends React.Component {
            constructor(props){
                super(props);
                    this.state = {name:'Hello React!'};
            }
            passParmsClick(name,e){//事件对象e要放在最后
                e.preventDefault();
                console.log(name);
            }
            render() {
                return(
                    <div>
                        <button onClick={(e)=>this.passParmsClick(this.state.name,e)}>Click</button>
                    </div>
                ) 
            };
        }
        ReactDOM.render(<Demo/>,document.getElementById('test'))
    </script>
</body>
</html>

另外一种方式就是通过bind()方法进行绑定来传递参数,请继续看 下面的代码实例:

<!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">
    <script src="https://unpkg.com/react@16/umd/react.development.js"></script>
    <script src="https://unpkg.com/react-dom@16/umd/react-dom.development.js"> </script> 
    <script src="https://unpkg.com/babel-standalone@6.15.0/babel.min.js"></script>

    <title>Document</title>
</head>
<body>
    <div id="test"></div>
    <script type="text/babel">
        class Demo extends React.Component {
            constructor(props){
                super(props);
                    this.state = {name:'Hello React!'};
            }
            passParmsClick(name,e){//事件对象e要放在最后
                e.preventDefault();
                console.log(name);
            }
            render() {
                return(
                    <div>
                        {/* 通过bind()方法绑定传递参数 */}
                        <button onClick={this.preventPop.bind(this,this.state.name)}>Click</button>
                    </div>
                ) 
            };
        }
        ReactDOM.render(<Demo/>,document.getElementById('test'))
    </script>
</body>
</html>

14.6.3.4、 实战:开关按钮

<!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">
    <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>

    <title>Document</title>
</head>
<body>
    <div id="test"></div>
    <script type="text/babel">
        class ToggleBtnComp extends React.Component {
            constructor(props){
                super(props);
                this.state = {isToggleOn:true};
                this.handleClick = this.toggleBtnClick.bind(this);
            }
            toggleBtnClick(isToggleOn,e) {
                e.preventDefault();
                console.log("Now state is '" + isToggleOn + "' before to convert.");
                this.setState(
                    state => ({
                        isToggleOn: !state.isToggleOn
                    })
                );
            }

            render() {
                console.log("Now state is  '" + this.state.isToggleOn + "'.");
                return(
                    <button onClick={(e) => this.toggleBtnClick(this.state.isToggleOn,e)}>
                        {this.state.isToggleOn ? 'Button ON':'Button OFF'}
                    </button>
                );
            }
        }
        ReactDOM.render(<ToggleBtnComp/>,document.getElementById('test'))
    </script>
</body>
</html>

测试网页

14.7、React生命周期

在React组件中,生命周期可基本分成三个状态,具体如下:

  • Mounting:已开始挂载真实的组件DOM。
  • Updating:正在重新渲染组件DOM。
  • Unmounting:已卸载真实的组件DOM。

同时,React框架定义了一组关于生命周期的方法,具体如下:

  • componentWillMount()方法:在渲染前调用,可以在客户端,也 可以在服务端。
  • componentDidMount()方法:在第一次渲染后调用,只作用于客 户端。
  • 户端。 componentWillUpdate()方法:在组件接收到新的Props参数或者 State状态、但还没有渲染时被调用。另外,该方法在初始化时不 会被调用。
  • componentDidUpdate()方法:在组件完成更新后会立即调用。另 外,该方法在初始化时不会被调用。
  • componentWillUnmount()方法:在组件从DOM中被移除之前会立 刻被调用。

14.8、React脚手架以及项目框架

本节介绍React脚手架方面的内容,脚手架是学习React开发非常重要的部分,其所涵盖的内容也非常广泛。因此,在介绍一些相关技术点时会简明扼要一下,更深入了解就需要读者自行完成了。

14.8.1、关于React脚手架

如今,Web前端应用几乎都拥有非常复杂的项目架构,绝非如【代 码1-1】那样的单页面文件就可以完成的。React项目开发也是如此,比较流行的做法是采用Webpack + ES6模式来搭建项目架构,然后通过打包方式发布Web应用。一般业内就称这个项目架构为“脚手架”,使用这 个名词概念确实很形象,就如同盖房子时必须使用的脚手架一样。

如果读者想使用“create-react-app”脚手架进行开发,必须先进行安 装。 前面我们已经学习了Node.js与npm,这里就不做过多的赘述。

现在,我们开始介绍如何使用欧冠“ceate-react-app”脚手架开发第一个应用。 如果要使用“create-react-app”脚手架,在早些时候就需要先安装 该脚手架。不过,自node v6+和npm v5.2+版本以后,npm新引入一条 npx命令,支持通过直接临时安装“create-react-app”脚手架来创建应用的 方式。关于这两种安装方式,下面都会具体介绍。

通过传统全局方式安装“create-react-app”脚手架的方法,具体操作 命令参考如下:

npm install -g create-react-app //全局安装方式

在“create-react-app”脚手架安装完毕后,选定好自己的项目目录, 通过create-react-app命令创建应用,具体命令如下:

create-react-app ch01-react-app-demo //创建React项目应用

如果是通过npx命令方式,安装“create-react-app”脚手架与创建项目 应用是一步完成的,具体操作命令参考如下:

npx create-react-app ch01-react-app-demo //npx方式

通过npx方式安装的“create-react-app”脚手架,其实是临时的安装 包,项目创建完成后会自动删除该安装包。

以上这两种通过“create-react-app”脚手架创建React项目的方式,虽 然过程有所区别,但最终效果是一样的。如下图所示是React项目创建完 成后的提示信息。

React项目创建完成后,通过“npm start”命令就可以启动项目了,具 体如下:

cd ch01-react-app-demo //进入项目目录

npm start //启动React项目

如果通过“npm start”命令启动React项目成功,控制台终端中会给出 正确的提示信息,如图所示。

通过浏览器访问地址(http://localhost:3000)就可以看到项目启动后的内容了,具体效果如图所示。

14.8.2、React项目架构

在这个项目应用介绍中,笔者不打算给出任何程序代码,就是让读 者了解一下通过“create-react-app”脚手架创建React项目的过程。下面看 一下通过脚手架创建React项目的架构。

上图是一个默认脚手架项目的目录和文件,关于各个目录和文件 的功能作用描述如下:

  • node_modules目录:是通过npm工具安装的所有依赖模块,是整 个项目的基础核心。
  • public目录:该目录下的index.html页面文件是整个项目的入口页 面,相当于网站主页。
  • src目录:用于保存整个项目的源代码,其中的index.js是源代码 入口。
  • package.json文件:整个项目的基本配置文件,用于定义项目的基 本信息。

以上就是一个最基本的、默认的“create-react-app”脚手架项目中, 关于目录和文件的基本介绍。整个“create-react-app”脚手架项目的架构高度可配置,设计人员可通过自定义方式实现更为复杂和高级的功能。

14.9、React综合案例--------todolist

开源地址一·:GitHub - smakosh/react-todolist: A simple todolist react app

开源地址二:GitHub - zih-an/react-todolist: [todolist] react ver.

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值