react基础
一、jsx基本使用
1、简单的react案例
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>hello React</title>
</head>
<body>
<div id='demo'> </div>
<!-- react核心库 -->
<script src="../js/react.development.js"></script>
<!-- 虚拟dom -->
<script src="../js/react-dom.development.js"></script>
<!-- 翻译:es6=>es5 , jsx=>js -->
<script src="../js/babel.min.js"></script>
<!-- 要把type="text/JavaScript"改为type="text/babel" -->
<script type="text/babel">
// 创建虚拟dom
const VDOM = <h1>hello react</h1> //此处VDOM不是字符串,不用加引号,jsx语法中可以写标签
//通过react渲染虚拟dom
// ReactDOM.render('渲染对象','渲染到哪')
ReactDOM.render(VDOM,document.getElementById('demo'))
/*
虚拟DOM:
1、虚拟DOM是一个普通的object对象
2、虚拟DOM和真实DOM的区别
const VDOM = <h1>hello react</h1>
const DOM = document.getElementById('demo');
console.log(VDOM);
console.log(trueDOM);
在debug模式下可发现:VDOM对象中包含的内容比trueDOM少的多
(1).虚拟DOM比较“轻”,真实DOM比较“重”
(2).虚拟DOM是react在用的,无需真实DOM身上那么多的属性。
*/
</script>
</body>
</html>
2、原生创建虚拟DOM
<!-- 使用原生js创建虚拟DOM -->
<script type="text/javascript">
const myId = 'AtGuigU'
const myContent = 'HeLlO,ReAct'
//1.创建虚拟DOM
//React.createElement(标签名,标签属性,内容)
const VDOM = React.createElement('h1',{id:myId.toLowerCase()},React.createElement('span',{},myContent.toLowerCase()))
//2.渲染虚拟DOM
ReactDOM.render(VDOM,document.getElementById('test'))
</script>
3、jsx创建虚拟DOM
<script type="text/babel" >
const myId = 'AtGuigU'
const myContent = 'HeLlO,ReAct'
//1.创建虚拟DOM
//React.createElement(标签名,标签属性,内容)
const VDOM = (
<div>
<h1 id={myId.toLowerCase()} zhangsan="qunideba">
<span className="title" style={{fontSize:'50px'}}>
{myContent.toLowerCase()}
</span>
</h1>
<h2>1121</h2>
<input type="text"/>
</div>
)
//2.渲染虚拟DOM
ReactDOM.render(VDOM,document.getElementById('test'))
</script>
注意:
关于jsx你要知道的:
1.jsx存在的意义:让程序员更加方便的创建虚拟DOM,几乎和写html是一样的。
2.jsx语法经过babel的编译,一定会转为原生js的语法。
3.jsx语法规则:
1.不要写引号,不是字符串
2.标签里要混入js表达式,要这样:{js表达式}
3.样式不要写class,要写className
4.style的写法:style={{}}
5.必须只有一个跟标签
6.所有标签必须闭合
二、组件的基本使用
1、函数式定义组件
jsx
解析标签规则:
1、发现<Demo/>
的首字母是大写。会去寻找Demo
组件定义的位置
2、发现首字母是小写。
2.1 且有同名的HTML
标签,会直接转化为HTML
标签
2.2 没有同名的HTML
标签,也会正常渲染为HTML
标签,但是控制台会报错
3、react帮我们调用Demo函数,并获取到Demo函数的返回值。
4.把返回的虚拟DOM,转换成真实DOM,放入指定容器。
//1.定义组件(函数式定义)---简单的组件用函数式定义
function Demo() {
console.log(this); //此处的this是undefined,因为经过babel编译之后开启了严格模式。
return <h1>我是用函数定义的组件(简单组件用我定义)</h1>
}
//2.渲染组件到页面
ReactDOM.render(<Demo/>,document.getElementById('example'))
/*
2、使用es6类定义组件
案例:
//1.定义组件(用ES6类定义)-------复杂组件
class Demo extends React.Component{
//该render和ReactDOM.render没有关系,仅仅是名字的重合。
render(){ //render是放在哪里的?--- Demo的原型对象上的,Demo的实例可以调用到
console.log(this);//Demo的实例
return <h1>我是ES6类定义的组件(复杂组件用我定义)</h1>
}
}
//2.渲染组件
ReactDOM.render(<Demo/>,document.getElementById('example'))
/*
三、组件实例的三个属性
1、state
使用构造器创建state
注1:
//demo为类中的方法
1.demo是放在原型上的。
2.demo中的this是undefined
3.this为undefined的原因:由于demo不属于react生命周期函数。
备注:在组件类中,所有非react生命周期函数中的this都被react更改了this,变为了undefined。
注2:
关于修改state要注意:
1.状态不可以直接修改,即:不能使用这种方式 this.state.isHot = xxxx
2.要调用一个内置的setState()方法去更新状态
注3:
1.render是放在原型上的。
2.render中的this是类的实例对象。
3.由于render是react众多生命周期函数中的一个。
备注:react所有生命周期函数中的this都是组件的实例对象。
案例:
class Weath extends React.Component{
constructor(){
super()
this.state ={
isHot:true
}
this.toWeath = this.toWeath.bind(this)//改变类中的toWeath方法的this执行,并传递给类的实例
}
toWeath(){
// console.log(this); //未改变this指向前,输出为undefined
const isHot = this.state.isHot
this.setState({isHot:!isHot})
}
render(){
// console.log(this);render为react的生命周期函数,内部this指向类的实例
return(
<div>
<h1>213{this.state.isHot?'热':'不热'}</h1>
<h2 onClick={this.toWeath}>点击改变</h2>
</div>
)
}
}
ReactDOM.render(<Weath/>,document.getElementById('demo'))
简写方式
注意:类中写赋值语句,代表的是向实例对象身上追加一个属性
形如: a = 1 代表向实例对象身上追加一个属性 名为a,值为1
另外:自己定义的非生命周期函数要写赋值语句,且函数要写箭头函数。
所以上面的代码可以简写为:
class Weath extends React.Component{
//state可以直接写赋值语句
state ={
isHot:true
}
//自己定义的非生命周期函数要写赋值语句,且函数要写箭头函数。
toWeath =()=>{
const isHot = this.state.isHot
this.setState({isHot:!isHot})
}
render(){
return(
<div>
<h1>213{this.state.isHot?'热':'不热'}</h1>
<h2 onClick={this.toWeath}>点击改变</h2>
</div>
)
}
}
ReactDOM.render(<Weath/>,document.getElementById('demo'))
2、props
在渲染时传入数据
注1:使用ReactDOM.render(<Weath/>,···)渲染时,可以传入数据
ReactDOM.render(<Weath name:“23” />,···)
注2:react + babel 就可以让三点运算符展开一个对象,但是仅适用于标签属性。
ReactDOM.render(<Weath {…p1} />,···)
注3:注意区分原生js中的{...p1}
案例:
ReactDOM.render(<Weath name="李四" age={12} />,document.getElementById('demo1'))
ReactDOM.render(<Weath {...p} />,document.getElementById('demo2'))
对props中的属性值进行类型限制和必要性限制
weath为组件类
第一种方式(React v15.5 开始已弃用):
Weath.propTypes = {
name: React.PropTypes.string.isRequired,
age: React.PropTypes.number
}
第二种方式(新):
使用prop-types库进限制(需要引入prop-types库)
Weath.propTypes = {
name: PropTypes.string.isRequired,
age: PropTypes.number.
}
指定传递标签属性的默认值
Weath.defaultProps = {
sex:'女'
}
static设置类的方法为静态的,不会传递给实例化对象
3、refs与事件处理
三种方式
普通ref方式(官方不推荐过多使用)
class Demo extends React.Component{
test1 = ()=> {
//1.获取左侧input的内容
const {value} = this.refs.left
//2.alert内容
alert(value)
}
test2 = (event)=>{
alert(event.target.value);
}
render(){
return (
<div>
<input type="text" ref="left"/>
<button onClick={this.test1}>点我提示左侧数据</button>
<input onBlur={this.test2} type="text" placeholder="失去焦点提示数据"/>
</div>
)
}
}
//2.渲染组件
ReactDOM.render(<Demo/>,document.getElementById('example'))
新语法:回调ref
class Demo extends React.Component{
test1 = ()=> {
alert(this.left.value)
}
test2 = (event)=>{
alert(event.target.value);
}
render(){
return (
<div>
<input type="text" ref={currentNode => this.left = currentNode}/>
<button onClick={this.test1}>点我提示左侧数据</button>
<input onBlur={this.test2} type="text" placeholder="失去焦点提示数据"/>
</div>
)
}
}
//2.渲染组件
ReactDOM.render(<Demo/>,document.getElementById('example'))
新语法:createRef 创造容器保存节点(只能保存一个节点)
class Demo extends React.Component{
//React.createRef()会创造一个容器,这个容器专门用于保存节点,且这容器只能保存一个节点。
myRef = React.createRef()
test1 = ()=> {
console.log(this.myRef.current);
}
test2 = (event)=>{
alert(event.target.value);
}
render(){
return (
<div>
<input type="text" ref={this.myRef}/>
<button onClick={this.test1}>点我提示左侧数据</button>
<input onBlur={this.test2} type="text" placeholder="失去焦点提示数据"/>
</div>
)
}
}
//2.渲染组件
ReactDOM.render(<Demo/>,document.getElementById('example'))
四、组件的组合使用
拆分组件:
需要一个外壳组件和内部负责不同功能的组件
把内部组件放在外壳组件中,这样只需要渲染外壳组件即可
案例:
//定义App组件,他是所有组件的“外壳”
class App extends React.Component{
render(){
return (
<div>
<h1>Simple Todo List</h1>
<Add/>
<List/>
</div>
)
}
}
//定义Add组件---用于添加的
class Add extends React.Component{
render(){
return (
<div>
<input type="text"/>
<button>Add#xxxx</button>
</div>
)
}
}
//定义Add组件---用于添加的
class List extends React.Component{
render(){
return (
<ul>
<li>吃饭</li>
<li>睡觉</li>
<li>打海峰</li>
</ul>
)
}
}
//渲染组件
ReactDOM.render(<App/>,document.getElementById('example'))
end:一些重点知识
1、call,apply,bind的区别
call :调用函数+改变this指向 传参
apply :调用函数+改变this指向
bind :改变this指向,返回新函数
2、三点运算符
三点运算符的作用:
解构数组:
let arr = [4,5,6,7]
let obj = {name:'peiqi',age:18,sex:{option1:'男',option2:'女'}}
console.log(...arr);//输出 4 5 6 7
// console.log(...obj);// 报错:demo.html:36 Uncaught TypeError: Found non-callable @@iterator
console.log({...obj});//输出的是一个和原对象内容相同的新对象
console.log({...obj}===obj);//输出:false
let obj2 = {...obj} //ES8的新语法--复制对象
console.log(obj2);//obj2和obj内容相同,但指向不是同一个
3、ES6的类
类里面能写什么?
1.构造器(非必须)
```
constructor(name,age){
//一般向实例身上追加属性
this.name = name
this.age = age
}
```
2.方法(非必须)
speak(){ //speak是放在类原型上的,供类的实例用。
console.log(`我是${this.name},我的年龄是:${this.age}`);
}
3.赋值语句(非必须),
形如: a = 1 ,含义是:向实例对象身上追加一个属性,名为a,值为1
类的继承
class 类名 extends 父类名
注意:如果A类继承了B类,那么在A类的构造器中就必须要调用super
4、js语句
与 js表达式
一定注意区分:【js语句】 与 【js表达式】:
1.表达式:一个表达式会产生一个值,它可以放在任何需要一个值的地方
举例:a
3 + b
demo("a", "b")
arr.map()
function foo() {}
.....
2.语句:语句可以理解成一个行为,循环语句、if语句,都是典型的语句
举例:
if(){}
for(){}
......