一、React背景简介
官网和资料
- 英文官网: https://reactjs.org/
- 中文官网: 快速入门 – React (docschina.org)
3、如果JS基础忘了及时查看文档:JavaScript - 学习 Web 开发 |多核 (mozilla.org)
JavaScript - 标签 - 汤姆大叔 - 博客园 (cnblogs.com)
4、React Guidebook - 📚 React 知识图谱 关于概念、技巧、生态、前沿、源码核心 - React Guidebook (tsejx.github.io)
5、Hello from React Status | React Status (docschina.org)
6、印记中文 - 深入挖掘国外前端领域,为中国 Web 前端开发人员提供优质文档 (docschina.org)
7、React快速上手开发
介绍描述
- 用于动态构建用户界面的 JavaScript 库(只关注于视图)
- 由Facebook开源
React的特点
- 声明式编码
- 组件化编码
- React Native 编写原生应用
- 高效(优秀的Diffing算法)
React高效的原因
- 使用虚拟(virtual)DOM, 不总是直接操作页面真实DOM。
- DOM Diffing算法, 最小化页面重绘。
面试:说说自己理解的react/介绍一下react
版本1:
React是用于构建用户界面的JavaScript库。React可以创建交互式UI。为应用程序中的每个状态建立的视图,并且React将在数据更改时进行更新,呈现正确的组件。另外,我们也可以构建管理自己状态的封装组件,然后将它们组合成复杂的UI。因为组件用JS编写而不是模板,所以可以通过应用传递数据,并使状态与DOM分离。
版本2:
React 是一个用于构建用户界面的 JAVASCRIPT 库。React主要用于构建UI,很多人认为 React 是 MVC 中的 V(视图) React特点有: 1.声明式设计 −React采用声明范式,可以轻松描述应用。 2.高效 −React通过对DOM的模拟,最大限度地减少与DOM的交互。 3.灵活 −React可以与已知的库或框架很好地配合。 4.JSX − JSX 是 JavaScript 语法的扩展。React 开发不一定使用 JSX ,但我们建议使用它。 5.组件 − 通过 React 构建组件,使得代码更加容易得到复用,能够很好的应用在大项目的开发中。 6.单向响应的数据流 − React 实现了单向响应的数据流,从而减少了重复代码,这也是它为什么比传统数据绑定更简单。
面试:项目里用到了react,为什么要选择react,react有哪些好处?
(1)声明式设计。
(2)高效:通过对DOM的模拟,最大限度的减少与DOM的交互。
(3)灵活:可以与已知的框架或库很好的配合。
(4)JSX:是js语法的扩展,不一定使用,但建议用。
(5)组件:构建组件,使代码更容易得到复用,能够很好地应用在大项目的开发中。
(6)单向响应的数据流:React实现了单向响应的数据流,从而减少了重复代码,这也是解释了它为什么比传统数据绑定更简单。
面试:angularJs和react区别
React对比Angular是思想上的转变,它也并不是一个库,是一种开发理念,组件化,分治的管理,数据与view的一体化。它只有一个中心,发出状态,渲染view,对于虚拟dom它并没有提高渲染页面的性能,它提供更多的是利用jsx便捷生成dom元素,利用组件概念进行分治管理页面每个部分(例如 header section footer slider)
面试:说说vue、 react 、angularjs 、jquery的区别
JQuery与另外几者最大的区别是,JQuery是事件驱动,其他两者是数据驱动。 JQuery业务逻辑和UI更改该混在一起, UI里面还参杂这交互逻辑,让本来混乱的逻辑更加混乱。 Angular,vue是双向绑定,而React不是 其他还有设计理念上的区别等
二、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>
<script type="text/babel" > /* 此处一定要写babel */
//1.创建虚拟DOM
const VDOM = <h1>Hello,React</h1> /* 此处一定不要写引号,因为不是字符串 */
//2.渲染虚拟DOM到页面
ReactDOM.render(VDOM,document.getElementById('test'))
</script>
</body>
</html>
三、React JSX(JSX:JavaScript XML)
- react定义的一种类似于XML的JS扩展语法: JS + XML本质是React.createElement(component, props, ...children)方法的语法糖。
- 作用: 用来简化创建虚拟DOM。
- 写法:var ele = <h1>Hello JSX!</h1> 注意1:它不是字符串, 也不是HTML/XML标签 ;注意2:它最终产生的就是一个JS对象。
- 标签名任意: HTML标签或其它标签 ; 标签属性任意: HTML标签属性或其它。
- 基本语法规则:① 、遇到 <开头的代码, 以标签的语法解析: html同名标签转换为html同名元素, 其它标签需要特别解析;②、遇到以 { 开头的代码,以JS语法解析: 标签中的js表达式必须用{ }包含。
- babel.js的作用:①、浏览器不能直接解析JSX代码, 需要babel转译为纯JS的代码才能运行;②、只要用了JSX,都要加上type="text/babel", 声明需要babel来处理。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>jsx语法规则</title>
<style>
.title{
background-color: orange;
width: 200px;
}
</style>
</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>
<script type="text/babel" >
const myId = 'aTgUiGu'
const myData = 'HeLlo,rEaCt'
//1.创建虚拟DOM
const VDOM = (
<div>
<h2 className="title" id={myId.toLowerCase()}>
<span style={{color:'white',fontSize:'29px'}}>{myData.toLowerCase()}</span>
</h2>
<h2 className="title" id={myId.toUpperCase()}>
<span style={{color:'white',fontSize:'29px'}}>{myData.toLowerCase()}</span>
</h2>
<input type="text"/>
</div>
)
//2.渲染虚拟DOM到页面
ReactDOM.render(VDOM,document.getElementById('test'))
/*
jsx语法规则:
1.定义虚拟DOM时,不要写引号。
2.标签中混入JS表达式时要用{}。
3.样式的类名指定不要用class,要用className。
4.内联样式,要用style={{key:value}}的形式去写。
5.只有一个根标签
6.标签必须闭合
7.标签首字母
(1).若小写字母开头,则将该标签转为html中同名元素,若html中无该标签对应的同名元素,则报错。
(2).若大写字母开头,react就去渲染对应的组件,若组件没有定义,则报错。
*/
</script>
</body>
</html>
四、渲染虚拟DOM(元素)
- 语法: ReactDOM.render(virtualDOM, containerDOM)
- 作用: 将虚拟DOM元素渲染到页面中的真实容器DOM中显示
- 参数说明:参数一: 纯js或jsx创建的虚拟dom对象 ;参数二: 用来包含虚拟DOM元素的真实dom元素对象(一般是一个div)
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>3_虚拟DOM与真实DOM</title>
</head>
<body>
<!-- 准备好一个“容器” -->
<div id="test"></div>
<div id="demo"></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>
<script type="text/babel" > /* 此处一定要写babel */
//1.创建虚拟DOM
const VDOM = ( /* 此处一定不要写引号,因为不是字符串 */
<h1 id="title">
<span>Hello,React</span>
</h1>
)
//2.渲染虚拟DOM到页面
ReactDOM.render(VDOM,document.getElementById('test'))
const TDOM = document.getElementById('demo')
console.log('虚拟DOM',VDOM);
console.log('真实DOM',TDOM);
debugger;
// console.log(typeof VDOM);
// console.log(VDOM instanceof Object);
/*
关于虚拟DOM:
1.本质是Object类型的对象(一般对象)
2.虚拟DOM比较“轻”,真实DOM比较“重”,因为虚拟DOM是React内部在用,无需真实DOM上那么多的属性。
3.虚拟DOM最终会被React转化为真实DOM,呈现在页面上。
*/
</script>
</body>
</html>
由此可见,虚拟DOM产生的对象比真实DOM产生的更少。React效率更高。
创建虚拟DOM的两种方式
①、使用JSX方式(JSX就是原始JS的一个语法糖)
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>1_使用jsx创建虚拟DOM</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>
<script type="text/babel" > /* 此处一定要写babel */
//1.创建虚拟DOM
const VDOM = ( /* 此处一定不要写引号,因为不是字符串 */
<h1 id="title">
<span>Hello,React</span>
</h1>
)
//2.渲染虚拟DOM到页面
ReactDOM.render(VDOM,document.getElementById('test'))
</script>
</body>
</html>
②、使用JS方式(一般不用,了解即可)
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>2_使用js创建虚拟DOM</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>
<script type="text/javascript" >
//1.创建虚拟DOM
const VDOM = React.createElement('h1',{id:'title'},React.createElement('span',{},'Hello,React'))
//2.渲染虚拟DOM到页面
ReactDOM.render(VDOM,document.getElementById('test'))
</script>
</body>
</html>
五、JSX练习
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>jsx小练习</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>
<script type="text/babel" >
/*
一定注意区分:【js语句(代码)】与【js表达式】
1.表达式:一个表达式会产生一个值,可以放在任何一个需要值的地方
下面这些都是表达式:
(1). a
(2). a+b
(3). demo(1)
(4). arr.map()
(5). function test () {}
2.语句(代码):
下面这些都是语句(代码):
(1).if(){}
(2).for(){}
(3).switch(){case:xxxx}
*/
//模拟一些数据
const data = ['Angular','React','Vue']
//1.创建虚拟DOM
const VDOM = (
<div>
<h1>前端js框架列表</h1>
<ul>
{
data.map((item,index)=>{
return <li key={index}>{item}</li>
})
}
</ul>
</div>
)
//2.渲染虚拟DOM到页面
ReactDOM.render(VDOM,document.getElementById('test'))
</script>
</body>
</html>
六、React 模块与组件、模块化与组件化的理解
模块
- 理解:向外提供特定功能的js程序, 一般就是一个js文件
- 为什么要拆成模块:随着业务逻辑增加,代码越来越多且复杂。
- 作用:复用js, 简化js的编写, 提高js运行效率
组件
- 理解:用来实现局部功能效果的代码和资源的集合(html/css/js/image等等)
- 为什么要用组件: 一个界面的功能更复杂
- 作用:复用编码, 简化项目编码, 提高运行效率
模块化
当应用的js都以模块来编写的, 这个应用就是一个模块化的应用
组件化
当应用是以多组件的方式实现, 这个应用就是一个组件化的应用
七、React面向组件编程
使用React开发者工具调试
安装之后,打开用React编写的官网,运行脚本将会发现。
函数式组件:写一个demo
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>1_函数式组件</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>
<script type="text/babel">
//1.创建函数式组件
function MyComponent(){
console.log(this); //此处的this是undefined,因为babel编译后开启了严格模式
return <h2>我是用函数定义的组件(适用于【简单组件】的定义)</h2>
}
//2.渲染组件到页面
ReactDOM.render(<MyComponent/>,document.getElementById('test'))
/*
执行了ReactDOM.render(<MyComponent/>.......之后,发生了什么?
1.React解析组件标签,找到了MyComponent组件。
2.发现组件是使用函数定义的,随后调用该函数,将返回的虚拟DOM转为真实DOM,随后呈现在页面中。
*/
</script>
</body>
</html>
注意
- 组件名必须首字母大写
- 虚拟DOM元素只能有一个根元素
- 虚拟DOM元素必须有结束标签
类式组件:写一个demo
复习类的知识
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>1_类的基本知识</title>
</head>
<body>
<script type="text/javascript" >
/*
总结:
1.类中的构造器不是必须要写的,要对实例进行一些初始化的操作,如添加指定属性时才写。
2.如果A类继承了B类,且A类中写了构造器,那么A类构造器中的super是必须要调用的。
3.类中所定义的方法,都放在了类的原型对象上,供实例去使用。
*/
//创建一个Person类
class Person {
//构造器方法
constructor(name,age){
//构造器中的this是谁?—— 类的实例对象
this.name = name
this.age = age
}
//一般方法
speak(){
//speak方法放在了哪里?——类的原型对象上,供实例使用
//通过Person实例调用speak时,speak中的this就是Person实例
console.log(`我叫${this.name},我年龄是${this.age}`);
}
}
//创建一个Student类,继承于Person类
class Student extends Person {
constructor(name,age,grade){
super(name,age)
this.grade = grade
this.school = '白学堂'
}
//重写从父类继承过来的方法
speak(){
console.log(`我叫${this.name},我年龄是${this.age},我读的是${this.grade}年级`);
this.study()
}
study(){
//study方法放在了哪里?——类的原型对象上,供实例使用
//通过Student实例调用study时,study中的this就是Student实例
console.log('我很努力的学习');
}
}
class Car {
constructor(name,price){
this.name = name
this.price = price
// this.wheel = 4
}
//类中可以直接写赋值语句,如下代码的含义是:给Car的实例对象添加一个属性,名为a,值为1
a = 1
wheel = 4
static demo = 100
}
const c1 = new Car('奔驰c63',199)
console.log(c1);
console.log(Car.demo);
</script>
</body>
</html>
写一个demo
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>2_类式组件</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>
<script type="text/babel">
//1.创建类式组件
class MyComponent extends React.Component {
render(){
//render是放在哪里的?—— MyComponent的原型对象上,供实例使用。
//render中的this是谁?—— MyComponent的实例对象 <=> MyComponent组件实例对象。
console.log('render中的this:',this);
return <h2>我是用类定义的组件(适用于【复杂组件】的定义)</h2>
}
}
//2.渲染组件到页面
ReactDOM.render(<MyComponent/>,document.getElementById('test'))
/*
执行了ReactDOM.render(<MyComponent/>.......之后,发生了什么?
1.React解析组件标签,找到了MyComponent组件。
2.发现组件是使用类定义的,随后new出来该类的实例,并通过该实例调用到原型上的render方法。
3.将render返回的虚拟DOM转为真实DOM,随后呈现在页面中。
*/
</script>
</body>
</html>
渲染类组件标签的基本流程
- React内部会创建组件实例对象
- 调用render()得到虚拟DOM, 并解析为真实DOM
- 插入到指定的页面元素内部
组件对象的三大核心
1、state——何为简单何为复杂?(复杂就是有状态,简单组件是没有状态的)
组件的状态会影响页面
理解
- state是组件对象最重要的属性, 值是对象(可以包含多个key-value的组合)
- 组件被称为"状态机", 通过更新组件的state来更新对应的页面显示(重新渲染组件)
强烈注意
- 组件中render方法中的this为组件实例对象
- 组件自定义的方法中this为undefined,如何解决?
- 强制绑定this: 通过函数对象的bind()
- 箭头函数
- 状态数据,不能直接修改或更新
练习: 定义一个展示天气信息的组件
默认展示天气炎热 或 凉爽
点击文字切换天气
复习一下原生事件的绑定
(其中按钮3方式是后面学习React使用最多的)
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<title>Document</title>
</head>
<body>
<button id="btn1">按钮1</button>
<button id="btn2">按钮2</button>
<button onclick="demo()">按钮3</button>
<script type="text/javascript" >
const btn1 = document.getElementById('btn1')
btn1.addEventListener('click',()=>{
alert('按钮1被点击了')
})
const btn2 = document.getElementById('btn2')
btn2.onclick = ()=>{
alert('按钮2被点击了')
}
function demo(){
alert('按钮3被点击了')
}
</script>
</body>
</html>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<title>Document</title>
</head>
<body>
<script type="text/javascript" >
class Person {
constructor(name,age){
this.name = name
this.age = age
}
study(){
//study方法放在了哪里?——类的原型对象上,供实例使用
//通过Person实例调用study时,study中的this就是Person实例
console.log(this);
}
}
const p1 = new Person('tom',18)
p1.study() //通过实例调用study方法
const x = p1.study
x()
</script>
</body>
</html>
2、props
需求: 自定义用来显示一个人员信息的组件
姓名必须指定,且为字符串类型;
性别为字符串类型,如果性别没有指定,默认为男
年龄为字符串类型,且为数字类型,默认值为18
理解
- 每个组件对象都会有props(properties的简写)属性
- 组件标签的所有属性都保存在props中
作用
- 通过标签属性从组件外向组件内传递变化的数据
- 注意: 组件内部不要修改props数据
编码:
3、 refs与事件处理
理解
组件内的标签可以定义ref属性来标识自己
编码
需求: 自定义组件, 功能说明如下:
点击按钮, 提示第一个输入框中的值
当第2个输入框失去焦点时, 提示这个输入框中的值
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>对props进行限制</title>
</head>
<body>
<!-- 准备好一个“容器” -->
<div id="test1"></div>
<div id="test2"></div>
<div id="test3"></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>
<!-- 引入prop-types,用于对组件标签属性进行限制 -->
<script type="text/javascript" src="../js/prop-types.js"></script>
<script type="text/babel">
//创建组件
class Person extends React.Component{
constructor(props){
//构造器是否接收props,是否传递给super,取决于:是否希望在构造器中通过this访问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为数值
}
//指定默认标签属性值
static defaultProps = {
sex:'男',//sex默认值为男
age:18 //age默认值为18
}
render(){
// console.log(this);
const {name,age,sex} = this.props
//props是只读的
//this.props.name = 'jack' //此行代码会报错,因为props是只读的
return (
<ul>
<li>姓名:{name}</li>
<li>性别:{sex}</li>
<li>年龄:{age+1}</li>
</ul>
)
}
}
//渲染组件到页面
ReactDOM.render(<Person name="jerry"/>,document.getElementById('test1'))
</script>
</body>
</html>
事件处理
- 通过onXxx属性指定事件处理函数(注意大小写)
- React使用的是自定义(合成)事件, 而不是使用的原生DOM事件
- React中的事件是通过事件委托方式处理的(委托给组件最外层的元素)
- 通过event.target得到发生事件的DOM元素对象
未完待续,将持续更新 ~