目录
14.4、组件三大核心属性之一 ---------State
14.6、组件三大核心属性三-------refs与事件处理
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的语法规则
- 定义DOM时,不要写引号
- 标签中混入JS表达式时要用{}
- 样式的类名指定不要用class,要用className。
- 内联样式,要用Style={{key:value}}的形式去写,并且比较复杂的属性要用小驼峰的方式书写,例如{{fontSize:‘20px’}}
- 虚拟DOM必须只有一个根标签
- 标签必须闭合
- 关于标签首字母
-
- 若小写字母开头,则将该标签转为html中同名元素,若HTML中无该标签对应的同名元素,则报错。
- 若大写字母开头,react就去渲染对应的组件,若组件没有定义,则报错。
【js语句(代码)】与【js表达式】的区别
- 表达式:一个表达式会产生一个值,可以放在任何一个需要值的地方,例如 下面这些都是表达式
-
- a;
- a+b;
- demo(1);
- arr.map() ;
- function test () { };可以const x = 这些js表达式,看是否可以输出 ,就可以判断是否为函数表达式
- 语句(代码)下面这些都是语句(代码)
-
- if ( ) { }
- for( ) { }
- 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>
![](https://i-blog.csdnimg.cn/blog_migrate/bf999e9fbe0429e78062082f62e73faa.png)
14.4、组件三大核心属性之一 ---------State
14.4.1、React State 介绍
React将组件看成一个状态机(State Machines),通过其内部定义的状态与生命周期实现与用户界面的交互,维持组件的不同状态。
在React框架中定义了一个状态(State)概念,并通过状态(State)来实现React组件的状态机特性。所谓React组件的“状态机”特性,就是指组件通过与用户的交互,实现不同的状态,然后通过渲染UI保证用户界面和数据的一致性。
简单来说,React中很多地方需要用到数据,这在React 中被叫做状态,我们需要一个专门管理状态的方法,于是State就诞生了。state被要求有两个基本功能,一、能够存储一定的值,从而能被React使用,二、能够在它改变的时候可以被React监听到并且重新渲染。
举个例子:
![](https://i-blog.csdnimg.cn/blog_migrate/8cfa2379d99bed21b0d7d7cd0360d272.png)
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>
强烈注意
- 组件中的render方法中的this为组件实例对象
- 组件自定义方法中的this为underfind,如何解决
a、强制绑定this:通过函数对象的bind()
this.changeWeather = this.changeWeather.bind(this)
b、箭头函数
changeWeather = ()=>{ const isHot = this.state.isHot this.setState({isHot:!isHot}) }
- 状态数据,不能直接修改或更新
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”属性的 值。
页面展示效果如下:
![](https://i-blog.csdnimg.cn/blog_migrate/d6fdd270bc31f48f50794695ceae8ae9.png)
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>
测试网页
![](https://i-blog.csdnimg.cn/blog_migrate/320fabf6f57b262b344f3f1a3caa37fa.png)
14.7、React生命周期
![](https://i-blog.csdnimg.cn/blog_migrate/ae97177f927dc71f985d0121f3597f51.png)
在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项目创建完 成后的提示信息。
![](https://i-blog.csdnimg.cn/blog_migrate/34d8b121829e9f000490eecf72719752.png)
React项目创建完成后,通过“npm start”命令就可以启动项目了,具 体如下:
cd ch01-react-app-demo //进入项目目录
npm start //启动React项目
如果通过“npm start”命令启动React项目成功,控制台终端中会给出 正确的提示信息,如图所示。
![](https://i-blog.csdnimg.cn/blog_migrate/a8d101d21b9c4be55bd903774c90faa9.png)
通过浏览器访问地址(http://localhost:3000)就可以看到项目启动后的内容了,具体效果如图所示。
![](https://i-blog.csdnimg.cn/blog_migrate/b1fa18cf8d8ac522bd826916673f7894.png)
14.8.2、React项目架构
在这个项目应用介绍中,笔者不打算给出任何程序代码,就是让读 者了解一下通过“create-react-app”脚手架创建React项目的过程。下面看 一下通过脚手架创建React项目的架构。
![](https://i-blog.csdnimg.cn/blog_migrate/6c79efa0f6bd8f2b2fbe178de9c5eb19.png)
上图是一个默认脚手架项目的目录和文件,关于各个目录和文件 的功能作用描述如下:
- 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