React学习01
React简介
React是一个将数据渲染为HTML视图的开源JavaScript库
使用React可解决原生DOM的三个问题。
- 原生JavaScript操作DOM繁琐、效率低(DOM-API操作UI)
- 使用JavaScript直接操作DOM,浏览器会进行大量的重绘重排
- 原生JavaScript没有组件化编码方案,代码复用率低
React的特点
- 采用组件化模式、声明式编码,提高开发效率及组件复用率
- 在React Native中可以使用React语法进行移动端进行开发
- 使用虚拟DOM+优秀的Diffing算法,尽量减少和真实DOM的交互(这也是React高效的原因)
React第一个例子
React的库由以下组成:
- babel.min.js:浏览器不兼容转化的
- react.development.js:React的核心库
- react-dom.development.js:React扩展库操作Dom的库
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>react</title>
</head>
<body>
<!--准备一个容器-->
<div id="test"></div>
<!--先引入react.js核心文件-->
<script src="../resources/react.js"></script>
<!--再引入reactdom.js操作dom的文件-->
<script src="../resources/react-dom.js"></script>
<!--最后引入babel文件-->
<script src="https://cdnjs.cloudflare.com/ajax/libs/babel-core/5.8.24/browser.min.js"></script>
<!--这儿type是text/babel表示写的不是js是jsx-->
<script type="text/babel">
//创建虚拟dom,一定不要加引号
const VDOM = <h1>hello,react</h1>
//渲染虚拟DOM到页面
ReactDOM.render(VDOM, document.getElementById('test'));
</script>
</body>
</html>
当调用render渲染页面时,React会自动比较两次渲染的元素,只有真实dom中更新发生变化的部分,没发生变化的保持不变
虚拟DOM的两种创建方式
JSX主要是为了创建虚拟DOM
- 不使用Jsx(很繁琐)
<script>
let VDOM = React.createElement('h1',{id:'title'},'hello,react');
ReactDOM.render(VDOM,document.getElementById('test'));
</script>
- 使用JSX
<script type="text/babel">
const VDOM=<h1 id="title">hello,react</h1>
ReactDOM.render(VDOM,document.getElementById('test'))
</script>
- 用小括号显示缩进
const VDOM=(
<h1 id="title">
<span id="title">hello,react</span>
</h1>
)
虚拟DOM与真实DOM的区别
关于虚拟DOM
- 本质是Object类型的对象(一般对象)
- 虚拟DOM比较“轻”,真实DOM比较“重”,因为虚拟DOM是React内部在用,无需真实DOM上那么多属性
- 虚拟DOM最终会被React转化为真实DOM,呈现在页面上
JSX
JSX练习
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<script src="../resources/react.js"></script>
<script src="../resources/react-dom.js"></script>
<script src="../resources/browser.min.js"></script>
</head>
<body>
<div id="test"></div>
<script type="text/babel">
//模拟一些数据
const data=['Angular','React','Vue']
const VDOM=(
<div>
<h1>前端JS框架列表</h1>
<ul>
{
data.map((item,index)=>{
//遍历的时候每个元素都必须有一个唯一的key
return <li key={index}>{item}</li>
})
}
</ul>
</div>
)
ReactDOM.render(VDOM,document.getElementById('test'));
</script>
</body>
</html>
模块与组件
函数式组件
函数的定义首字母大写,渲染的时候,要写函数名标签
<div id="test"></div>
<script type="text/babel">
function Demo() {
console.log(this)// 此处的this是undefined 因为babel开启了严格模式,所有this无法指向window
return <h2>函数式组件</h2>
}
ReactDOM.render(<Demo/>,document.getElementById('test'))
</script>
类式组件
类复习
继承
- 和Java不同的是Js中类的继承允许继承构造器,Java是不允许的
- 代码实例
组件的三大属性
创建类式组件的时候,组件名首字母必须大写
<div id="test"></div>
<script type="text/babel">
//创建类式组件(必须继承Component和实现render方法)
class MyComponent extends React.Component{
render(){
//render是放在哪里的?--类的原型对象上,供实例使用
//render中的this是谁?--MyComponent实例对象
console.log(this);//组件的三大属性是类的实例的
return <h2>类式组件适用于复杂组件</h2>
}
}
ReactDOM.render(<MyComponent/>,document.getElementById('test'));
</script>
组件属性
组件属性有state、props、refs
state
state改变的时候组件会重新执行render方法,重新渲染页面
- 需求点击页面显示不同的效果
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>test</title>
<script src="../resources/react.js"></script>
<script src="../resources/react-dom.js"></script>
<script src="../resources/browser.min.js"></script>
</head>
<body>
<div id="test"></div>
<script type="text/babel">
//创建组件
class Weather extends React.Component{
constructor(props) {
super(props);
//初始化状态(这儿的state赋值是对象)
this.state={isHot:true}
}
render(){
//解构赋值
//读取状态
const {isHot}=this.state;
return <h1>今天天气很{isHot?'炎热':'凉爽'}</h1>
}
}
//渲染组件到页面
ReactDOM.render(<Weather/>,document.getElementById('test'));
</script>
</body>
</html>
React事件
深入理解this
- 类中局部开启了严格模式所以this是undefined
在调用的时候,this.changeWeather给了onClick,onClick直接进行了调用,所以是无法得到this的
bind的使用
bind的用法有两种
- 生成新的函数
- 改变this的指向
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>bind</title>
</head>
<body>
<script>
function bind() {
console.log(this)
}
//输出window对象(如果方法里是严格模式则输出undefined)
bind();
//使用bind绑定新的对象,生成新的函数bind1
let bind1 = bind.bind({a:1,b:2});
//调用bind1输出新的对象而不是window对象
bind1();
</script>
</body>
</html>
setState的使用
//state(状态)不可以直接更改要借助内置的API进行更改
//获取原来的isHot
let isHot = this.state.isHot;
this.setState({isHot:!isHot});
- 最终修改后
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>test</title>
<script src="../resources/react.js"></script>
<script src="../resources/react-dom.js"></script>
<script src="../resources/browser.min.js"></script>
</head>
<body>
<div id="test"></div>
<script type="text/babel">
//创建组件
class Weather extends React.Component{
//构造器调用几次?--<Weather/>只调用了1次,所以构造器也只使用了一次
constructor(props) {
super(props);
//初始化状态(这儿的state赋值是对象)
this.state={isHot:true}
/*
* 对于右边changeWeather放在原型对象上,
* 所以可以通过实例对象(this)找到原型对象,找到changeWeather,
* this是当前实例对象
* bind:1、生成新的函数 2、改this的指向
* 这儿新生成的函数是nice,是this的。所以在调用的时候也要调用this的nice函数
* */
this.nice=this.changeWeather.bind(this);
}
//render调用几次?--1+n次
render(){
//解构赋值
//读取状态
const {isHot}=this.state;
//this.changeWeather --changeWeather放在哪里?--Weather的原型对象上 所以必须用this
//由于changeWeather是作为onClick的回调,所以不是通过实例进行调用的,是直接进行调用的
//类中的方法默认开启了局部严格模式,所以changeWeather中的this是undefined
return <h1 onClick={this.nice}>今天天气很{isHot?'炎热':'凉爽'}</h1>
}
//React添加事件
//changeWeather调用几次?--点击多少次调用多少次
changeWeather(){
//changeWeather放在哪里?--Weather的原型对象上
//由于changeWeather是作为onClick的回调,所以不是通过实例进行调用的,是直接进行调用的
//类中的方法默认开启了局部严格模式,所以changeWeather中的this是undefined
//state(状态)不可以直接更改要借助内置的API进行更改
//获取原来的isHot
//注意:状态必须通过setState进行更新,且更新是合并不是替换
let isHot = this.state.isHot;
this.setState({isHot:!isHot});
}
}
//渲染组件到页面
ReactDOM.render(<Weather/>,document.getElementById('test'));
</script>
</body>
</html>
state的简写方式
类中可以直接写赋值语句,相当于给类的实例添加属性,
类构造参数的简写方式
- state的简写
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>bubia</title>
<script src="../resources/react.js"></script>
<script src="../resources/react-dom.js"></script>
<script src="../resources/browser.min.js"></script>
</head>
<body>
<div id="test"></div>
<script type="text/babel">
class Weather extends React.Component{
//state简写
//初始化state
state={isHot:true}
render(){
const {isHot}=this.state;
return <h1 onClick={this.changeWeather}>今天天气{isHot?'炎热':'凉爽'}</h1>
}
//使用箭头函数就可以把this搞进来了,箭头函数的this是静态的(es6)
//自定义方法--要用赋值语句的形式+箭头函数
//使用箭头函数的目的是为了得到实例对象(this)
changeWeather=()=>{
console.log(this)
const isHot = this.state.isHot;
this.setState({isHot:!isHot});
}
}
ReactDOM.render(<Weather/>,document.getElementById('test'))
</script>
</body>
</html>
props
需求:自定义用来显示一个人员信息的组件
使用state进行实现(不建议使用)
<script type="text/babel">
//创建组件
class Person extends React.Component{
state={name:'tom',gender:'男',age:19};
render(){
return (
<ul>
<li>姓名:{this.state.name}</li>
<li>性别:{this.state.gender}</li>
<li>年龄:{this.state.age}</li>
</ul>
)
}
}
ReactDOM.render(<Person/>,document.getElementById('test'))
</script>
使用props
<div id="test"></div>
<script type="text/babel">
//创建组件
class Person extends React.Component{
render(){
//解构赋值
const {name,gender,age}=this.props;
return (
<ul>
<li>姓名:{name}</li>
<li>性别:{gender}</li>
<li>年龄:{age}</li>
</ul>
)
}
}
ReactDOM.render(<Person name='dasg' gender='男' age='19' />,document.getElementById('test'))
</script>
批量传递props
- 进化之前
<div id="test"></div>
<script type="text/babel">
//创建组件
class Person extends React.Component{
render(){
//解构赋值
const {name,gender,age}=this.props;
return (
<ul>
<li>姓名:{name}</li>
<li>性别:{gender}</li>
<li>年龄:{age}</li>
</ul>
)
}
}
const p={name:'lxd',gender:'男',age:'19'};
//太繁琐了一个一个往render里面塞
ReactDOM.render(<Person name={p.name} gender={p.gender} age={p.age} />,document.getElementById('test'))
</script>
- 批量
通过{…p}进行批量props,不过名字默认就是传过来的json里的key}
<div id="test"></div>
<script type="text/babel">
//创建组件
class Person extends React.Component{
render(){
//解构赋值
const {name,gender,age}=this.props;
return (
<ul>
<li>姓名:{name}</li>
<li>性别:{gender}</li>
<li>年龄:{age}</li>
</ul>
)
}
}
const p={name:'lxd',gender:'男',age:'19'};
//通过{...p进行批量props,不过名字默认就是传过来的json里的key}
ReactDOM.render(<Person {...p} />,document.getElementById('test'))
</script>
- 来源
使用了扩展运算符(babel+react可以使用展开运算符展开一个对象)
对props进行限制
<div id="test"></div>
<script type="text/babel">
//创建组件
class Person extends React.Component{
render(){
//解构赋值
const {name,gender,age}=this.props;
return (
<ul>
<li>姓名:{name}</li>
<li>性别:{gender}</li>
<li>年龄:{age+1}</li>
</ul>
)
}
}
//限制读取的属性(添加规则)
Person.protoTypes={
name:PropTypes.string.isRequired,
gender:PropTypes.string,
age:PropTypes.number
}
//默认规则配置
Person.defaultProps={
gender:'男',
age:18
}
const p={name:'lxd',gender:'男',age:19};
//通过{...p进行批量props,不过名字默认就是传过来的json里的key}
ReactDOM.render(<Person {...p} />,document.getElementById('test'))
</script>
props简写方式
props是只读的
<div id="test"></div>
<script type="text/babel">
//创建组件
class Person extends React.Component{
//限制读取的属性(添加规则)
static protoTypes={
name:PropTypes.string.isRequired,
gender:PropTypes.string,
age:PropTypes.number
}
//默认规则配置
static defaultProps={
gender:'男',
age:18
}
render(){
//解构赋值
const {name,gender,age}=this.props;
return (
<ul>
<li>姓名:{name}</li>
<li>性别:{gender}</li>
<li>年龄:{age+1}</li>
</ul>
)
}
}
const p={name:'lxd',gender:'男',age:19};
//通过{...p进行批量props,不过名字默认就是传过来的json里的key}
ReactDOM.render(<Person {...p} />,document.getElementById('test'))
</script>
类式组件中的构造器与props
所以类中的构造器能省略就省略
函数式组件使用props
函数式组件只能使用组件三大属性的props,把props作为参数进行使用
<div id="test"></div>
<script type="text/babel">
//props作为参数进行使用
function Demo(props) {
//解构赋值
const {name,gender,age}=props;
return (
<h3>
<ul>
<li>姓名:{name}</li>
<li>性别:{gender}</li>
<li>年龄:{age}</li>
</ul>
</h3>
)
}
const p={name:'lxd',gender:'男',age:19};
ReactDOM.render(<Demo {...p}/>,document.getElementById('test'))
</script>
props总结
refs
案例:左侧输入完后,点击提示输入数据弹出框,右侧输入完后失去焦点,弹出弹出框
字符串形式的ref(不推荐使用)
为啥叫refs呢–因为refs里有多个ref。字符串形式的ref:ref是用字符串进行定义的
ref=“input1” //input1就是当前dom(ref的作用就是存储节点的信息)
<div id="test"></div>
<script type="text/babel">
class Demo extends React.Component{
render() {
return (
<div>
<input ref="input1" type="text" placeholder="点击按钮提示左侧的数据"/>
<button onClick={this.showData}>点击提示数据</button>
<input ref="input2" onBlur={this.showData1} type="text" placeholder="失去焦点提示数据"/>
</div>
);
}
showData=()=>{
const {input1}=this.refs;
alert(input1.value)
}
showData1=()=>{
const {input2}=this.refs;
alert(input2.value)
}
}
ReactDOM.render(<Demo/>,document.getElementById('test'))
</script>
回调形式的ref
不使用字符串ref的原因是效率太低
- ref={currentNode=>this.input1=currentNode} //currentNode代表当前的dom
<div id="test"></div>
<script type="text/babel">
class Demo extends React.Component{
render() {
return (
<div>
<input ref={currentNode=>this.input1=currentNode} type="text" placeholder="点击按钮提示左侧的数据"/>
<button onClick={this.showData}>点击提示数据</button>
<input ref={currentNode=>this.input2=currentNode} onBlur={this.showData2} type="text" placeholder="失去焦点提示数据"/>
</div>
);
}
showData=()=>{
//结构赋值
const {input1}=this;
alert(input1.value)
}
showData2=()=>{
//解构赋值
const {input2}=this;
alert(input2.value)
}
}
ReactDOM.render(<Demo/>,document.getElementById('test'))
</script>
createRef的使用
使用React.createRef();用几个得创建几个
<div id="test"></div>
<script type="text/babel">
class Demo extends React.Component{
//创建一个ref的容器(装节点的)
myRef=React.createRef();
myRef2=React.createRef();
render() {
return (
<div>
<input ref={this.myRef} type="text" placeholder="输入显示左边"/>
<button onClick={this.showData}>点击显示左边内容</button>
<input ref={this.myRef2} onBlur={this.showData2} type="text" placeholder="失去焦点提示数据"/>
</div>
);
}
showData=()=>{
alert(this.myRef.current.value)
}
showData2=()=>{
alert(this.myRef2.current.value)
}
}
ReactDOM.render(<Demo/>,document.getElementById('test'));
</script>
React的事件
发生事件的事件源和要操作的事件源是同一个的时候可以不加标识即ref,
不要过度使用ref,发生事件的元素和要操作的元素是同一个的时候不加ref
<script type="text/babel">
class Demo extends React.Component{
//创建一个ref的容器(装节点的)
myRef=React.createRef();
render() {
return (
<div>
<input ref={this.myRef} type="text" placeholder="输入显示左边"/>
<button onClick={this.showData}>点击显示左边内容</button>
<input onBlur={this.showData2} type="text" placeholder="失去焦点提示数据"/>
</div>
);
}
showData=()=>{
alert(this.myRef.current.value)
}
showData2=(event)=>{
alert(event.target.value)
}
}
ReactDOM.render(<Demo/>,document.getElementById('test'));
</script>