一.介绍React
用于构建用户界面的 JavaScript 库
二.react特点
- 声明式:React 可以非常轻松地创建用户交互界面。为你应用的每一个状态设计简洁的视图,在数据改变时 React 也可以高效地更新渲染界面。
- 组件化:创建好拥有各自状态的组件,再由组件构成更加复杂的界面。
- 一次学习,随处编写:无论你现在正在使用什么技术栈,你都可以随时引入 React 开发新特性。React 也可以用作开发原生应用的框架 React Native.
三.第一个React程序
注意:在开始第一个react程序之前要搞清楚react的本质就是js代码,所以第一个程序我们直接在HTML代码中演示
react.html
<!DOCTYPE html>
<html lang="">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>react基础</title>
</head>
<body>
<div id="app">
</div>
<script src="https://cdn.bootcss.com/react/16.4.0/umd/react.development.js"></script>
<script src="https://cdn.bootcss.com/react-dom/16.4.0/umd/react-dom.development.js"> </script>
<script src="https://cdn.bootcss.com/babel-standalone/6.26.0/babel.min.js"></script>
<script type="text/babel">
const element=<div title="welcome">hello React</div>
ReactDOM.render(element,document.getElementById("app"))
</script>
</body>
</html>
分析第一个react程序的三个步骤
1.引包
cdn方式
<script src="https://cdn.bootcss.com/react/16.4.0/umd/react.development.js"></script>
<script src="https://cdn.bootcss.com/react-dom/16.4.0/umd/react-dom.development.js"></script>
<!-- 生产环境中不建议使用 -->
<script src="https://cdn.bootcss.com/babel-standalone/6.26.0/babel.min.js"></script>
本地方式
<!-- react的核心库 -->
<script src="lib/react.development.js"></script>
<!-- 提供与DOM相关的功能 -->
<script src="lib/react-dom.development.js"></script>
<!-- 将es6的语法转成es5,包括react的jsx语法,需要通过babel转换 -->
<script src="lib/babel.min.js"></script>
注意:本地方式引包要注意相对路径,以及各个文件库的顺序,在实际的开发中比较少采用本地引包的方式,而是使用webpack打包工具以及npm
2.创建react元素
<script type="text/babel">
// 创建react元素
// 参数1: 元素的名称
// 参数2: 元素的属性
// 参数3: 元素的内容(子元素)
const element = React.createElement('div', {
title: 'welcome',className:'on'
}, 'Hello React!!!')
</script>
注意:
-
如果在浏览器端使用babel,必须指定type='text/babel'
-
createElement()方法
这个方法一共有三个参数,若某一个参数没有值,则需要用null来代替,否则将会报错
这种方式来创建元素实在是太过麻烦,所以我们使用jsx语法来写
<script type="text/babel"> const element=<div title="welcome">hello React</div> </script>
3.渲染元素到页面中
准备html的结构
<div id="app"></div>
把元素渲染到页面
// 把元素渲染到页面中
// 参数1:需要渲染的react对象
// 参数2:指定渲染到页面中的容器
ReactDOM.render(
element,
document.getElementById('app')
)
四.jsx语法
jsx: 一种 JavaScript 的语法扩展。 在react中推荐使用react来描述用户界面(创建react对象)
通过jsx创建react对象,实质内部还是调用createElement方法,只不过jsx语法更加的简洁
1.jsx语法需要注意的要点
- jsx虽然看起来像模板,但是jsx是一个js对象,并不是字符串,也不是DOM对象
- 在jsx中可以使用表达式,在标签中使用需要使用
{}包裹起来即可,但{}只能出现表达式,不能出现语句 - 为了代码可读性,书写jsx的时候需要保证代码的缩进,并且给jsx的代码使用
()包裹起来 - jsx中的注释 不是//而是{/* */}
- jsx中的元素只能有一个根元素,并且标签必须闭合,可以是单标签,但是单标签也要闭合。
- 因为 JSX 的特性更接近 JavaScript 而不是 HTML ,所以jsx的属性是js的属性,比如class变成了className
注意:以上所说的要点在书写代码是一定要注意,否则会出现报错
2.jsx语法体验
<!DOCTYPE html>
<html lang="">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>react基础</title>
<style>
.on{
color:red;
}
</style>
</head>
<body>
<div id="app">
</div>
<script src="https://cdn.bootcss.com/react/16.4.0/umd/react.development.js"></script>
<script src="https://cdn.bootcss.com/react-dom/16.4.0/umd/react-dom.development.js"></script>
<script src="https://cdn.bootcss.com/babel-standalone/6.26.0/babel.min.js"></script>
<script type="text/babel">
function fn() {
return 'hello react'
}
const msg = {
str:'你好呀',
age: 18
}
const element=(<div>
<h1>{msg.str}</h1>
<div title="welcome" className="on">{fn()}</div>
</div>)
ReactDOM.render(element,document.getElementById("app"))
</script>
</body>
</html>
3.案例:实现时钟功能
<!DOCTYPE html>
<html lang="">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
</head>
<body>
<div id="app"></div>
<script src="https://cdn.bootcss.com/react/16.4.0/umd/react.development.js"></script>
<script src="https://cdn.bootcss.com/react-dom/16.4.0/umd/react-dom.development.js"></script>
<!-- 生产环境中不建议使用 -->
<script src="https://cdn.bootcss.com/babel-standalone/6.26.0/babel.min.js"></script>
<script type="text/babel">
function tick(){
//定义react对象
const element=(
<div>
<h1>北京时间</h1>
<h2>当前时间:{new Date().toLocaleString()}</h2>
</div>
)
//把react对象渲染到页面中
ReactDOM.render(element,document.getElementById("app"))
}
setInterval(tick, 1000);
</script>
</body>
</html>
五.React中的虚拟DOM与diff算法
注意:面试官的最爱
React 中最值得称道的部分莫过于 Virtual DOM 与 diff 的完美结合,特别是其高效的 diff 算法,让用户可以无需顾忌性能问题而”任性自由”的刷新页面
我没有能力用代码这种高大尚的方式来演绎什么是虚拟DOM,什么是diff算法,以及虚拟DOM与真实的DOM的区别,下面就讲一下理解吧
1.真实的DOM
DOM就是文档对象模型的意思,html中的每一个标签元素可以理解为一个DOM节点,一个网页就是由许许多多的DOM节点构成
2.虚拟的DOM
- 使用js对象来描述一个DOM结构,在react框架中,这种方式描述一个DOM的对象称为虚拟DOM
- 页面的更新可以先全部反映在js对象上,操作内存中的js对象的速度显然要快多了,不需要重绘与回流
- 等更新完后,再将最终的js对象映射成真实的DOM,交由浏览器去绘制。
3.diff算法
diff算法,就是用来找出两段文本之间的差异的一种算法。
4.为什么要使用diff算法
DOM操作是非常昂贵的,因此我们需要尽量地减少DOM操作。这就需要找出本次DOM必须更新的节点来更新,其他的不更新,这个找出的过程,就需要应用diff算法。
5.为什么使用虚拟的DOM
要理解为什么要使用虚拟的DOM,这里有必要了解浏览器的渲染机制
浏览器是怎么样渲染一个代码量庞大的页面的呢?
6.React中DOM的更新方式
1.使用虚拟DOM(JavaScript)对象结构表示 DOM 树的结构,根据虚拟DOM渲染出真正的DOM树
2.当状态变更的时候,重新构造一棵新的对象树。然后用新的树和旧的树进行比较,记录两棵树差异(diff算法)
3.把2所记录的差异应用到步骤1所构建的真正的DOM树上,视图就更新了
六.组件
组件:组件就是一个自定义的标签,在react中,组件有两类,函数组件 ,类组件
1.函数组件
-
自定义一个函数,返回一个react对象,函数名首字母要大小,用于区分普通的html标签
-
render渲染到页面上时要注意 :
把组件当做自定义标签来使用,并包含在根节点之内
<!DOCTYPE html>
<html lang="">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
</head>
<body>
<div id="app"></div>
<script src="https://cdn.bootcss.com/react/16.4.0/umd/react.development.js"></script>
<script src="https://cdn.bootcss.com/react-dom/16.4.0/umd/react-dom.development.js"></script>
<!-- 生产环境中不建议使用 -->
<script src="https://cdn.bootcss.com/babel-standalone/6.26.0/babel.min.js"></script>
<script type="text/babel">
//定义函数组件
function Template1(){
return (
<h1>大家好呀,我是第一个测试组件</h1>
)
}
function Template2(){
return (
<h2>我是第二个测试组件</h2>
)
}
//渲染到页面中
//把组件当做自定义标签来使用,并包含在根节点之内
ReactDOM.render(
<div>
<Template1></Template1>
<Template2></Template2>
</div>,document.getElementById('app')
)
</script>
</body>
</html>
函数组件是怎么传值的
- props参数传值
- 带有形参的组件在外部声明,使用时可以嵌套在别的组件里面并传入实参
- 渲染的是别的组件
- 有一个缺点,没有状态,状态也就是数据,函数组件自己没有数据
<!DOCTYPE html>
<html lang="">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
</head>
<body>
<div id="app"></div>
<script src="https://cdn.bootcss.com/react/16.4.0/umd/react.development.js"></script>
<script src="https://cdn.bootcss.com/react-dom/16.4.0/umd/react-dom.development.js"></script>
<!-- 生产环境中不建议使用 -->
<script src="https://cdn.bootcss.com/babel-standalone/6.26.0/babel.min.js"></script>
<script type="text/babel">
//定义函数组件
function Template1(props){
return (
<div>
<h1>大家好呀,我是第一个测试组件</h1>
<p>{props.name}</p>
<p>{props.age}</p>
</div>
)
}
function Template2(){
return (
<div>
{/* 在Template2组件内部,嵌套Template1 */}
<Template1 name="zs" age="18"/>
</div>
)
}
//渲染到页面中的组件是Template2
ReactDOM.render(
<div>
<Template2></Template2>
</div>,document.getElementById('app')
)
</script>
</body>
</html>
注意:函数组件的props是只读的,并不能修改,比如这样是错误的
//定义函数组件
function Template1(props){
// props.name = '李四'
// props.age = 22
return (
<div>
<h1>大家好呀,我是第一个测试组件</h1>
<p>{props.name}</p>
<p>{props.age}</p>
</div>
)
}
案例:实现时钟功能
<body>
<div id="app"></div>
<script src="https://cdn.bootcss.com/react/16.4.0/umd/react.development.js"></script>
<script src="https://cdn.bootcss.com/react-dom/16.4.0/umd/react-dom.development.js"> </script>
<!-- 生产环境中不建议使用 -->
<script src="https://cdn.bootcss.com/babel-standalone/6.26.0/babel.min.js"></script>
<script type="text/babel">
//定义一个Clock组件,专门用于显示时间
function Clock (props) {
return (
<div>
<h1>北京时间</h1>
<h2>当前时间:{props.date.toLocaleString()}</h2>
</div>
)
}
setInterval(() => {
// 如何渲染的Clock组件
ReactDOM.render(
<Clock date={new Date()}/>,
document.getElementById('app')
)
}, 1000)
</script>
</body>
2.类组件
为了帮助大家理解类组件,这里先给大家介绍一下ES6语法中的类
ES6中的类
<!DOCTYPE html>
<html lang="">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>react基础</title>
</head>
<body>
<script>
class Person{
//指定构造函数
constructor(name,age){
this.name=name;
this.age=age;
}
//给对象添加方法
sayhi(){
console.log("hello world");
}
}
var person=new Person();
person.sayhi();//helle world
</script>
</body>
</html>
ES6中的类继承
- 通过super()来继承父类的构造方法,其他方法自动继承
- 在继承的同时也可以定义自己的属性,方法
<!DOCTYPE html>
<html lang="">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>react基础</title>
</head>
<body>
<script>
class Person{
//指定构造函数
constructor(name,age){
this.name=name;
this.age=age;
}
//给对象添加方法
sayhi(){
console.log("大家好呀");
}
}
class chinese extends Person{
constructor(name,age){
super(name,age);//继承父类的构造方法
this.color='yellow';
}
read(){
console.log("我喜欢读中文的书");
}
}
var student=new chinese("zhangsan","18");
student.sayhi();//大家好呀
console.log(student.name);//zhangsan
console.log(student.age);//18
</script>
</body>
</html>
类组件基本模型
- 定义一个类组件必须继承于React.Component
- 在类中使用render()函数返回模板
- 渲染到页面中
<!DOCTYPE html>
<html lang="">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>react基础</title>
</head>
<body>
<div id="app"></div>
<script src="https://cdn.bootcss.com/react/16.4.0/umd/react.development.js"></script>
<script src="https://cdn.bootcss.com/react-dom/16.4.0/umd/react-dom.development.js"> </script>
<!-- 生产环境中不建议使用 -->
<script src="https://cdn.bootcss.com/babel-standalone/6.26.0/babel.min.js"></script>
<script type="text/babel">
//定义一个类组件
class Hello extends React.Component{
constructor(){
super();
}
render(){
return (
<h1>hello world</h1>
)
}
}
//渲染组件
ReactDOM.render(
<Hello/>,document.getElementById('app')
)
</script>
</body>
</html>
怎么给类组件传值
- 在类组件中想要获取传递过来的值,也是通过props来获取
- 除了props,类组件还可以自己提供状态(数据)
<!DOCTYPE html>
<html lang="">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>react基础</title>
</head>
<body>
<div id="app"></div>
<script src="https://cdn.bootcss.com/react/16.4.0/umd/react.development.js"></script>
<script src="https://cdn.bootcss.com/react-dom/16.4.0/umd/react-dom.development.js"> </script>
<!-- 生产环境中不建议使用 -->
<script src="https://cdn.bootcss.com/babel-standalone/6.26.0/babel.min.js"></script>
<script type="text/babel">
//定义一个类组件
class Hello extends React.Component{
constructor(props){
super(props);
{/*除了props,类组件还可以自己提供状态(数据)*/}
this.state={
msg:'你好呀'
}
}
render(){
return (
<div>
<h1>{this.props.name}</h1>
<h1>{this.props.age}</h1>
<h1>{this.state.msg}</h1>
</div>
)
}
}
//渲染组件
ReactDOM.render(
<Hello name="zhangsan" age="18"/>,document.getElementById('app')
)
</script>
</body>
</html>
3.函数组件和类组件混合使用
<!DOCTYPE html>
<html lang="">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>react基础</title>
</head>
<body>
<div id="app"></div>
<script src="https://cdn.bootcss.com/react/16.4.0/umd/react.development.js"></script>
<script src="https://cdn.bootcss.com/react-dom/16.4.0/umd/react-dom.development.js"> </script>
<!-- 生产环境中不建议使用 -->
<script src="https://cdn.bootcss.com/babel-standalone/6.26.0/babel.min.js"></script>
<script type="text/babel">
//定义一个函数组件
function Template1(){
return (
<h1>大家好呀,我是第一个测试组件</h1>
)
}
//定义一个类组件
class Template2 extends React.Component{
constructor(props){
super(props);
}
render(){
return (
<Template1 />
)
}
}
//渲染组件
ReactDOM.render(
<Template2 />,document.getElementById('app')
)
</script>
</body>
</html>
七.事件
- 在react中注册事件与给DOM注册事件基本是一样的, onclick onmouseenter onblur onkeyup
- 在react中注册事件,采用驼峰命名法, onClick onMouseEnter onBlur
- 在react中注册事件,通过{}传入的是一个函数, 而不是一个字符串
- 在react中,如果想要阻止浏览器的默认行为,不要使用return false,使用e.preventDefault()
<!DOCTYPE html>
<html lang="">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>react基础</title>
</head>
<body>
<div id="app"></div>
<script src="https://cdn.bootcss.com/react/16.4.0/umd/react.development.js"></script>
<script src="https://cdn.bootcss.com/react-dom/16.4.0/umd/react-dom.development.js"> </script>
<!-- 生产环境中不建议使用 -->
<script src="https://cdn.bootcss.com/babel-standalone/6.26.0/babel.min.js"></script>
<script type="text/babel">
//定义一个类组件
class Hello extends React.Component{
render(){
return (
<div>
<button onClick={this.fn}>点我</button>
<a href="http://www.baidu.com" onClick={this.fn}>跳转</a>
</div>
)
}
fn(e){
//阻止默认事件
e.preventDefault();
console.log("hello world");
}
}
//渲染组件
ReactDOM.render(
<Hello />,document.getElementById('app')
)
</script>
</body>
</html>
1.react事件中的this丢失以及解决方案
点击修改数据按钮实现修改显示的文字
<!DOCTYPE html>
<html lang="">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>react基础</title>
</head>
<body>
<div id="app"></div>
<script src="https://cdn.bootcss.com/react/16.4.0/umd/react.development.js"></script>
<script src="https://cdn.bootcss.com/react-dom/16.4.0/umd/react-dom.development.js"> </script>
<!-- 生产环境中不建议使用 -->
<script src="https://cdn.bootcss.com/babel-standalone/6.26.0/babel.min.js"></script>
<script type="text/babel">
//定义一个类组件
class Hello extends React.Component{
constructor(props){
super(props);
this.state={
msg:'你好呀'
}
}
render(){
return (
<div>
<h1>{this.state.msg}</h1>
<button onClick={this.fn}>修改msg数据</button>
</div>
)
}
fn(){
console.log(this)
this.setState({
msg:'呵呵'
})
}
}
//渲染组件
ReactDOM.render(
<Hello />,document.getElementById('app')
)
</script>
</body>
</html>
注意:
按照我们原来的规则,上面的代码在运行时出现报错,fn函数中打印的this是undefined
原因是什么呢?
- 在react注册事件的时候,提供的事件处理函数的内部this指向undefined
- 没办法访问到this,没有办法访问到当前实例,没有办法访问到数据
- 如果想要修改react的状态,不能直接通过this.setState()去修改
下面提供三种解决方案
-
bind方法: 任何一个函数,都有bind方法,bind方法可以用来修改函数内部的this指向,可以在构造函数中,去处理事件处理函数的this问题
<!DOCTYPE html> <html lang=""> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta http-equiv="X-UA-Compatible" content="ie=edge"> <title>react基础</title> </head> <body> <div id="app"></div> <script src="https://cdn.bootcss.com/react/16.4.0/umd/react.development.js"></script> <script src="https://cdn.bootcss.com/react-dom/16.4.0/umd/react-dom.development.js"> </script> <!-- 生产环境中不建议使用 --> <script src="https://cdn.bootcss.com/babel-standalone/6.26.0/babel.min.js"></script> <script type="text/babel"> //定义一个类组件 class Hello extends React.Component{ constructor(props){ super(props); this.state={ msg:'你好呀' } //在构造函数中,去处理事件处理函数的this问题 this.fn=this.fn.bind(this) } render(){ return ( <div> <h1>{this.state.msg}</h1> <button onClick={this.fn}>修改msg数据</button> </div> ) } fn(){ console.log(this) this.setState({ msg:'呵呵' }) } } //渲染组件 ReactDOM.render( <Hello />,document.getElementById('app') ) </script> </body> </html> -
属性初始化器语法, 提供了一个箭头函数,将匿名函数改为箭头函数
<!DOCTYPE html> <html lang=""> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta http-equiv="X-UA-Compatible" content="ie=edge"> <title>react基础</title> </head> <body> <div id="app"></div> <script src="https://cdn.bootcss.com/react/16.4.0/umd/react.development.js"></script> <script src="https://cdn.bootcss.com/react-dom/16.4.0/umd/react-dom.development.js"> </script> <!-- 生产环境中不建议使用 --> <script src="https://cdn.bootcss.com/babel-standalone/6.26.0/babel.min.js"></script> <script type="text/babel"> //定义一个类组件 class Hello extends React.Component{ constructor(props){ super(props); this.state={ msg:'你好呀' } } render(){ return ( <div> <h1>{this.state.msg}</h1> <button onClick={this.fn}>修改msg数据</button> </div> ) } fn=()=>{ console.log(this) this.setState({ msg:'呵呵' }) } } //渲染组件 ReactDOM.render( <Hello />,document.getElementById('app') ) </script> </body> </html> -
点击事件里面提供一个匿名函数,在匿名函数中调用修改数据的方法(不建议这种写法)
<!DOCTYPE html> <html lang=""> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta http-equiv="X-UA-Compatible" content="ie=edge"> <title>react基础</title> </head> <body> <div id="app"></div> <script src="https://cdn.bootcss.com/react/16.4.0/umd/react.development.js"></script> <script src="https://cdn.bootcss.com/react-dom/16.4.0/umd/react-dom.development.js"> </script> <!-- 生产环境中不建议使用 --> <script src="https://cdn.bootcss.com/babel-standalone/6.26.0/babel.min.js"></script> <script type="text/babel"> //定义一个类组件 class Hello extends React.Component{ constructor(props){ super(props); this.state={ msg:'你好呀' } } render(){ return ( <div> <h1>{this.state.msg}</h1> <button onClick={ ()=>{ this.fn(); } }>修改msg数据</button> </div> ) } fn(){ console.log(this) this.setState({ msg:'呵呵' }) } } //渲染组件 ReactDOM.render( <Hello />,document.getElementById('app') ) </script> </body> </html>
2.事件传参问题
在项目中经常会将一些操作的逻辑代码封装成一个函数,比如删除某条记录,这就会涉及函数传参问题,那么react中函数一般是怎么写的呢?请看上面的案例,函数传参也是在这基础上的
函数传参的两种方法
- 在注册事件的时候,通过bind的方式进行传参,若还想要获取事件对象, 把事件对象作为最后一个参数
<!DOCTYPE html>
<html lang="">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>react基础</title>
</head>
<body>
<div id="app"></div>
<script src="https://cdn.bootcss.com/react/16.4.0/umd/react.development.js"></script>
<script src="https://cdn.bootcss.com/react-dom/16.4.0/umd/react-dom.development.js"> </script>
<!-- 生产环境中不建议使用 -->
<script src="https://cdn.bootcss.com/babel-standalone/6.26.0/babel.min.js"></script>
<script type="text/babel">
//定义一个类组件
class Hello extends React.Component{
constructor(props){
super(props);
this.state={
msg:'你好呀'
}
//在构造函数中,去处理事件处理函数的this问题
this.fn=this.fn.bind(this,id)
}
render(){
return (
<div>
<h1>{this.state.msg}</h1>
<button onClick={this.fn}>修改msg数据</button>
</div>
)
}
fn(id,e){
console.log(id);
console.log(e);
}
}
//渲染组件
ReactDOM.render(
<Hello />,document.getElementById('app')
)
</script>
</body>
</html>
- 点击事件里面提供一个匿名函数,在匿名函数中调用方法时传参
<!DOCTYPE html>
<html lang="">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>react基础</title>
</head>
<body>
<div id="app"></div>
<script src="https://cdn.bootcss.com/react/16.4.0/umd/react.development.js"></script>
<script src="https://cdn.bootcss.com/react-dom/16.4.0/umd/react-dom.development.js"> </script>
<!-- 生产环境中不建议使用 -->
<script src="https://cdn.bootcss.com/babel-standalone/6.26.0/babel.min.js"></script>
<script type="text/babel">
//定义一个类组件
class Hello extends React.Component{
constructor(props){
super(props);
this.state={
msg:'你好呀'
}
}
render(){
return (
<div>
<h1>{this.state.msg}</h1>
<button onClick={
()=>{
this.fn(3);
}
}>修改msg数据</button>
</div>
)
}
fn(id){
console.log(id);
}
}
//渲染组件
ReactDOM.render(
<Hello />,document.getElementById('app')
)
</script>
</body>
</html>
八.组件渲染
1.条件渲染
根据条件不同,渲染不同的内容,和js中的if-else不同
<!DOCTYPE html>
<html lang="">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>react基础</title>
</head>
<body>
<div id="app"></div>
<script src="https://cdn.bootcss.com/react/16.4.0/umd/react.development.js"></script>
<script src="https://cdn.bootcss.com/react-dom/16.4.0/umd/react-dom.development.js"> </script>
<!-- 生产环境中不建议使用 -->
<script src="https://cdn.bootcss.com/babel-standalone/6.26.0/babel.min.js"></script>
<script type="text/babel">
function UserGreeting() {
return <div>欢迎回来,尊贵的v12用户</div>
}
function GuestGreeting() {
return <div>你好,请先登录</div>
}
class App extends React.Component {
constructor(props) {
super(props)
this.state = {
isLogin: true
}
}
// 完成了条件渲染,根据isLogin来渲染不同的内容
render() {
if (this.state.isLogin) {
return <UserGreeting />
} else {
return <GuestGreeting />
}
}
}
ReactDOM.render(<App />, document.getElementById('app'))
</script>
</body>
</html>
在条件渲染中变量的使用
- 声明变量来保存react的对象,初始值设为null
- 不同条件下的结果赋值给该变量
<!DOCTYPE html>
<html lang="">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>react基础</title>
</head>
<body>
<div id="app"></div>
<script src="https://cdn.bootcss.com/react/16.4.0/umd/react.development.js"></script>
<script src="https://cdn.bootcss.com/react-dom/16.4.0/umd/react-dom.development.js">
</script>
<!-- 生产环境中不建议使用 -->
<script src="https://cdn.bootcss.com/babel-standalone/6.26.0/babel.min.js"></script>
<script type="text/babel">
class Score extends React.Component {
constructor(props) {
super(props)
this.state = { score: 100 }
}
render() {
// 可以使用变量来保存react的对象
let content = null
if (this.state.score >= 90) {
// 元素变量, 把一个react对象赋值给一个变量
content = <p>A</p>
} else if (this.state.score >= 80) {
content = <p>B</p>
} else if (this.state.score >= 70) {
content = <p>C</p>
} else if (this.state.score >= 60) {
content = <p>D</p>
} else {
content = <p>E</p>
}
return (
<div>
<h3>提示消息</h3>
<p>你本次的成绩是</p>
{content}
</div>
)
}
}
ReactDOM.render(<Score />, document.getElementById('app'))
</script>
</body>
</html>
在条件渲染中运算符的使用
<!DOCTYPE html>
<html lang="">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>react基础</title>
</head>
<body>
<div id="app"></div>
<script src="https://cdn.bootcss.com/react/16.4.0/umd/react.development.js"></script>
<script src="https://cdn.bootcss.com/react-dom/16.4.0/umd/react-dom.development.js">
</script>
<!-- 生产环境中不建议使用 -->
<script src="https://cdn.bootcss.com/babel-standalone/6.26.0/babel.min.js"></script>
<script type="text/babel">
class App extends React.Component {
constructor(props) {
super(props)
this.state = {
score: 90,
age: 18
}
}
render() {
return (
<div>
<h3>提示消息</h3>
{this.state.age >= 18 ? <div>成年人</div> : <div>未成年人</div>}
</div>
)
}
}
ReactDOM.render(<App />, document.getElementById('app'))
</script>
</body>
</html>
在条件渲染中return null的使用
return null就表示后面的代码都不执行了
<!DOCTYPE html>
<html lang="">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>react基础</title>
</head>
<body>
<div id="app"></div>
<script src="https://cdn.bootcss.com/react/16.4.0/umd/react.development.js"></script>
<script src="https://cdn.bootcss.com/react-dom/16.4.0/umd/react-dom.development.js">
</script>
<!-- 生产环境中不建议使用 -->
<script src="https://cdn.bootcss.com/babel-standalone/6.26.0/babel.min.js"></script>
<script type="text/babel">
class App extends React.Component {
constructor(props) {
super(props)
this.state = {
age: 18
}
}
render() {
if(this.state.age<18){
return null;
}
return (
<div>
<h3>提示消息</h3>
<div>系统已监测你已经成年,可以玩这款游戏</div>
</div>
)
}
}
ReactDOM.render(<App />, document.getElementById('app'))
</script>
</body>
</html>
2.列表渲染
在学习列表渲染之前,这里一下数组的遍历方法map():
map()方法返回一个新数组,数组中的元素为原始数组元素调用函数处理后的值。
[].map(function(value, index, array) {
//第一个参数是值
//第二个参数是索引值
//第三个是原始的数组
});
var array1 = [1,4,9,16];
var a=array1.map(v =>v*2);
console.log(a);//2,8,18,32
数组遍历
人物列表
<!DOCTYPE html>
<html lang="">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>react基础</title>
</head>
<body>
<div id="app"></div>
<script src="https://cdn.bootcss.com/react/16.4.0/umd/react.development.js"></script>
<script src="https://cdn.bootcss.com/react-dom/16.4.0/umd/react-dom.development.js">
</script>
<!-- 生产环境中不建议使用 -->
<script src="https://cdn.bootcss.com/babel-standalone/6.26.0/babel.min.js"></script>
<script type="text/babel">
class List extends React.Component{
constructor(props){
super(props)
this.state={
list:["张飞","赵云","马超","貂蝉"]
}
}
render(){
let content=this.state.list.map((item,index)=>(
<li key={index}>{item}</li>
))
return (
<div>
<h3>人物列表</h3>
<ul>{content}</ul>
</div>
)
}
}
ReactDOM.render(<List />, document.getElementById('app'))
</script>
</body>
</html>
对象遍历
人物列表
<!DOCTYPE html>
<html lang="">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>react基础</title>
</head>
<body>
<div id="app"></div>
<script src="https://cdn.bootcss.com/react/16.4.0/umd/react.development.js"></script>
<script src="https://cdn.bootcss.com/react-dom/16.4.0/umd/react-dom.development.js">
</script>
<!-- 生产环境中不建议使用 -->
<script src="https://cdn.bootcss.com/babel-standalone/6.26.0/babel.min.js"></script>
<script type="text/babel">
class List extends React.Component{
constructor(props){
super(props)
this.state={
list:[
{ id: 1, name: 'zs', age: 18, gender: '男' },
{ id: 2, name: 'ls', age: 19, gender: '男' },
{ id: 3, name: 'ww', age: 20, gender: '女' }
]
}
}
render(){
let content=this.state.list.map(item=>(
<tr key={item.id}>
<td>{item.id}</td>
<td>{item.name}</td>
<td>{item.age}</td>
<td>{item.gender}</td>
</tr>
))
return (
<div>
<h3>人物列表</h3>
<table>
<tbody>{content}</tbody>
</table>
</div>
)
}
}
ReactDOM.render(<List />, document.getElementById('app'))
</script>
</body>
</html>
评论列表
可以直接在jsx中使用map函数
<!DOCTYPE html>
<html lang="">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>react基础</title>
</head>
<body>
<div id="app"></div>
<script src="https://cdn.bootcss.com/react/16.4.0/umd/react.development.js"></script>
<script src="https://cdn.bootcss.com/react-dom/16.4.0/umd/react-dom.development.js">
</script>
<!-- 生产环境中不建议使用 -->
<script src="https://cdn.bootcss.com/babel-standalone/6.26.0/babel.min.js"></script>
<script type="text/babel">
class Comment extends React.Component {
constructor(props) {
super(props)
// 添加状态
this.state = {
list: [
{ id: 1, name: '张三', content: '沙发' },
{ id: 2, name: '李四', content: '板凳' },
{ id: 3, name: '王五', content: '卖瓜子' },
{ id: 4, name: '赵六', content: '今天吃了没' }
]
}
}
render() {
return (
<div>
<h1>评论案例</h1>
<ul>
{this.state.list.map(item => (
<li key={item.id}>
<h3>
评论人:
{item.name}
</h3>
<p>
评论内容:
{item.content}
</p>
</li>
))}
</ul>
</div>
)
}
}
ReactDOM.render(<Comment />, document.getElementById('app'))
</script>
</body>
</html>
评论列表
通过多个组件传值实现
<!DOCTYPE html>
<html lang="">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>react基础</title>
</head>
<body>
<div id="app"></div>
<script src="https://cdn.bootcss.com/react/16.4.0/umd/react.development.js"></script>
<script src="https://cdn.bootcss.com/react-dom/16.4.0/umd/react-dom.development.js">
</script>
<!-- 生产环境中不建议使用 -->
<script src="https://cdn.bootcss.com/babel-standalone/6.26.0/babel.min.js"></script>
<script type="text/babel">
// 评论组件
class Comment extends React.Component {
constructor(props) {
super(props)
// 添加状态
this.state = {
list: [
{ id: 1, name: '张三', content: '沙发' },
{ id: 2, name: '李四', content: '板凳' },
{ id: 3, name: '王五', content: '卖瓜子' },
{ id: 4, name: '赵六', content: '今天吃了没' }
]
}
}
render() {
return (
<div>
<h1>评论案例</h1>
<ul>
{this.state.list.map(item => (
<Item key={item.id} data={item} />
))}
</ul>
</div>
)
}
}
// 评论项组件,没有状态,数据是父组件传递过来的
function Item(props) {
return (
<li>
<h3>
评论人:
{props.data.name}
</h3>
<p>评论内容 {props.data.content}</p>
</li>
)
}
ReactDOM.render(<Comment />, document.getElementById('app'))
</script>
</body>
</html>
九.表单
react中的表单分为两种:受控表单,非受控表单
react操作表单的目的是获取用户输入的内容
1.受控表单
受控表单的基本模型
- 当前组件中的表单受到了react的控制,当表单元素的内容发生了改变,react对应的状态也要发生改变
- react的状态发生改变,对应的表单内容也要发生改变
- 类似于vue的双向数据绑定
- 在表单标签中绑定一个onChange事件,一定是onChange事件
- 在函数体重传入e参数,利用
e.target.value来获取表单元素的值
<!DOCTYPE html>
<html lang="">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>react基础</title>
</head>
<body>
<div id="app">
</div>
<script src="https://cdn.bootcss.com/react/16.4.0/umd/react.development.js"></script>
<script src="https://cdn.bootcss.com/react-dom/16.4.0/umd/react-dom.development.js"> </script>
<!-- 生产环境中不建议使用 -->
<script src="https://cdn.bootcss.com/babel-standalone/6.26.0/babel.min.js"></script>
<script type="text/babel">
//定义一个类组件
class Hello extends React.Component{
constructor(props){
super(props);
this.state={
msg:'你好呀'
}
}
render(){
return (
<div>
<p>
<input type="text" onChange={this.handleChange}/>
</p>
<p>
{this.state.msg}
</p>
</div>
)
}
handleChange=e=>{
this.setState({
msg:e.target.value
})
}
}
//渲染组件
ReactDOM.render(
<Hello />,document.getElementById('app')
)
</script>
</body>
</html>
受控表单的统一处理模型
从受控表单的基本模型知道,如果要对一个组件中很多的表单标签做控制也就意味着要写很多个事件,所以需要封装一个函数来统一处理
<!DOCTYPE html>
<html lang="">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>react基础</title>
</head>
<body>
<div id="app">
</div>
<script src="https://cdn.bootcss.com/react/16.4.0/umd/react.development.js"></script>
<script src="https://cdn.bootcss.com/react-dom/16.4.0/umd/react-dom.development.js"> </script>
<!-- 生产环境中不建议使用 -->
<script src="https://cdn.bootcss.com/babel-standalone/6.26.0/babel.min.js"></script>
<script type="text/babel">
//定义一个类组件
class Hello extends React.Component{
constructor(props){
super(props);
this.state={
username:"zhangsan",
content:"我是内容呀",
city:"1"
}
}
render(){
return (
<div>
<div>
<h3>input</h3>
<input
type="text"
value={this.state.username}
onChange={this.handleChange}
name="username"
/>
<p>{this.state.username}</p>
<h3>textarea</h3>
<textarea
cols="30"
rows="10"
value={this.state.content}
onChange={this.handleChange}
name="content"
/>
<p>{this.state.content}</p>
<h3>select</h3>
<select
value={this.state.city}
onChange={this.handleChange}
name="city"
>
<option value="1">北京</option>
<option value="2">上海</option>
<option value="3">广州</option>
<option value="4">深圳</option>
</select>
<p>{this.state.city}</p>
</div>
</div>
)
}
handleChange=e=>{
//先获取标签元素
var name=e.target.name
//再获取标签元素的值,es6的属性名表达式
this.state[name]=e.target.value
//修改值
this.setState(this.state)
}
}
//渲染组件
ReactDOM.render(
<Hello />,document.getElementById('app')
)
</script>
</body>
</html>
2.非受控表单
我们一般采用受控表单来获取表单元素的值,也可以采用非受控表单的形式
要编写一个非受控组件,而不是为每个状态更新都编写数据处理函数,你可以 使用 ref来从 DOM 节点中获取表单数据。
非受控表单基本模型
- 在构造函数中,需要自己创建一个引用 ref
- 我们创建的ref与表单元素绑定,我们创建的ref可以在任意地方使用
- 通过ref.current.value来获取值
<!DOCTYPE html>
<html lang="">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>react基础</title>
</head>
<body>
<div id="app">
</div>
<script src="https://cdn.bootcss.com/react/16.4.0/umd/react.development.js"></script>
<script src="https://cdn.bootcss.com/react-dom/16.4.0/umd/react-dom.development.js"> </script>
<!-- 生产环境中不建议使用 -->
<script src="https://cdn.bootcss.com/babel-standalone/6.26.0/babel.min.js"></script>
<script type="text/babel">
//定义一个类组件
class Form extends React.Component {
constructor(props) {
super(props)
// 1. 创建ref
this.usernameRef = React.createRef()
this.buttonRef = React.createRef()
}
render() {
return (
<div>
{/* 2. 我们创建的ref可以 在组件的任意地方使用 */}
<input ref={this.usernameRef} type="text" />
<button ref={this.buttonRef} onClick={this.get}>
获取value值
</button>
</div>
)
}
get = () => {
// 手动获取到DOM的value值
// refs: 用于操作DOM的
// 3. 通过this.usernameRef.current
console.log(this.usernameRef.current.value)
}
}
//渲染组件
ReactDOM.render(
<Form />,document.getElementById('app')
)
</script>
</body>
</html>
3.图书管理案例
实现图书的增删查改
<!DOCTYPE html>
<html lang="">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>react基础</title>
</head>
<body>
<div id="app">
</div>
<script src="https://cdn.bootcss.com/react/16.4.0/umd/react.development.js"></script>
<script src="https://cdn.bootcss.com/react-dom/16.4.0/umd/react-dom.development.js"> </script>
<!-- 生产环境中不建议使用 -->
<script src="https://cdn.bootcss.com/babel-standalone/6.26.0/babel.min.js"></script>
<script type="text/babel">
//定义一个类组件
class Book extends React.Component {
constructor(props) {
super(props)
this.state = {
list: [
{ id: 1, name: '红楼梦', desc: '一堆乱七八糟的破事' },
{ id: 2, name: '西游记', desc: '小时候的经典' },
{ id: 3, name: '权威指南', desc: 'js程序员必读' }
],
name: '',
desc: '',
id: '',
index: 3
}
}
render() {
return (
<div className="container">
<div className="form">
书名:
<input
type="text"
value={this.state.name}
onChange={this.handleChange}
name="name"
/>
描述:
<input
type="text"
value={this.state.desc}
onChange={this.handleChange}
name="desc"
/>
<button onClick={this.addBook}>添加</button>
</div>
<table>
<thead>
<tr>
<th>编号</th>
<th>书名</th>
<th>描述</th>
<th>操作</th>
</tr>
</thead>
<tbody>
{this.state.list.map((item, index) => (
<tr key={item.id}>
<td>{index + 1}</td>
<td>{item.name}</td>
<td>{item.desc}</td>
<td>
<a href="#" onClick={this.delBook.bind(this, item.id)}>
删除
</a>
|
<a href="#" onClick={this.showEdit.bind(this, item)}>
修改
</a>
</td>
</tr>
))}
</tbody>
</table>
</div>
)
}
addBook = () => {
// 判断是否有id值,如果有,是修改,否则是添加
if (this.state.id) {
// 修改
// 根据id找到需要修改的下标
let idx = this.state.list.findIndex(item => item.id === this.state.id)
this.state.list[idx].name = this.state.name
this.state.list[idx].desc = this.state.desc
} else {
// 添加
// 添加图书
this.state.list.push({
id: ++this.state.index,
name: this.state.name,
desc: this.state.desc
})
}
// 清空name和desc
this.state.name = ''
this.state.desc = ''
this.state.id = ''
this.setState(this.state)
}
handleChange = e => {
let { name, value } = e.target
this.setState({
[name]: value
})
}
delBook(id, e) {
e.preventDefault()
// 删除需要id
// 根据id获取到下标
let idx = this.state.list.findIndex(item => item.id === id)
// 删除对应的数据
this.state.list.splice(idx, 1)
this.setState(this.state)
}
showEdit = (book, e) => {
e.preventDefault()
this.state.id = book.id
this.state.name = book.name
this.state.desc = book.desc
this.setState(this.state)
}
}
ReactDOM.render(<Book />, document.getElementById('app'))
</script>
</body>
</html>
十.组件之间的通讯
- 在实际的项目中总是会各种组件嵌套使用,但是每个组件的状态是私有的,别的组件时不能直接访问的
- 组件之间的通讯主要分为:父组件向子组件传值,子组件向父组件传值
1.父组件传值给子组件
- 嵌套在别的类中的组件是子组件
- 父组件若向子组件传值,在引用子组件时就把值传过去
- 子组件通过props在自己的内部即可接受父组件传过来的值
- 渲染的父组件
<!DOCTYPE html>
<html lang="">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>react基础</title>
</head>
<body>
<div id="app">
</div>
<script src="https://cdn.bootcss.com/react/16.4.0/umd/react.development.js"></script>
<script src="https://cdn.bootcss.com/react-dom/16.4.0/umd/react-dom.development.js"> </script>
<!-- 生产环境中不建议使用 -->
<script src="https://cdn.bootcss.com/babel-standalone/6.26.0/babel.min.js"></script>
<script type="text/babel">
//定义一个父组件
class Father extends React.Component{
constructor(props){
super();
this.state={
msg:'大家好呀,我是爸爸'
}
}
render(){
return (
<div>
<h3>我是父组件</h3>
<Son msg={this.state.msg} name="zhangsan" age="18" />
</div>
)
}
}
//定义一个子组件
class Son extends React.Component{
constructor(props){
super(props);
}
render(){
return (
<div>
<p>{this.props.msg}</p>
<p>{this.props.name}</p>
<p>{this.props.age}</p>
</div>
)
}
}
ReactDOM.render(<Father />, document.getElementById('app'))
</script>
</body>
</html>
2.子组件向父组件传值
-
首先父组件提供一个接收数据的方法
-
子组件嵌套在父组件中
-
子组件提供一个传数据的方法,在方法体中将props赋值给父组件接收数据的方法,调用父组件接收数据的方法
-
渲染的是父组件
<!DOCTYPE html>
<html lang="">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>react基础</title>
</head>
<body>
<div id="app">
</div>
<script src="https://cdn.bootcss.com/react/16.4.0/umd/react.development.js"></script>
<script src="https://cdn.bootcss.com/react-dom/16.4.0/umd/react-dom.development.js"> </script>
<!-- 生产环境中不建议使用 -->
<script src="https://cdn.bootcss.com/babel-standalone/6.26.0/babel.min.js"></script>
<script type="text/babel">
//定义一个父组件
class Father extends React.Component{
constructor(props){
super();
this.state={
msg:'大家好呀,我是爸爸'
}
}
render(){
return (
<div>
<h3>我是父组件</h3>
<Son getData={this.getData} />
</div>
)
}
//提供一个接收数据的方法
getData(msg){
console.log(msg)
}
}
//定义一个子组件
class Son extends React.Component{
constructor(props){
super(props);
this.state={
msg:'大家好,我是子组件'
}
}
render(){
return (
<div>
<button onClick={this.sendData}>给父组件传递数据</button>
</div>
)
}
sendData=()=>{
//给父组件传递数据
let {getData}=this.props
getData(this.state.msg)
}
}
ReactDOM.render(<Father />, document.getElementById('app'))
</script>
</body>
</html>