旧版
hello world
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
| <!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>
|
vdom
vdom介绍
关于虚拟DOM:
- 本质是Object类型的对象
- 虚拟DOM比较“轻”,真实DOM比较“重”,因为虚拟DOM是React内部在用,无需真实DOM上那么多的属性。
- 虚拟DOM最终会被React转化为真实DOM,呈现在页面上。
vdom的创建方式
使用jsx:语法糖
1 2 3 4 5 6 7 8
| <script type="text/babel"> const VDOM = ( <h1 id="title"> <span>Hello,React</span> </h1> ) ReactDOM.render(VDOM,document.getElementById('test')) </script>
|
使用js:不便于处理嵌套标签
bable会把jsx翻译成js,即转化为下方的代码↓
1 2 3 4
| <script type="text/javascript" > const VDOM = React.createElement('h1',{id:'title'},React.createElement('span',{},'Hello,React')) ReactDOM.render(VDOM,document.getElementById('test')) </script>
|
jsx语法
jsx语法规则:
- 定义虚拟DOM时,不要写引号
- 标签中混入JS表达式时要用{}
- 样式的类名指定不要用class,要用className
- 内联样式,要用
style={{key:value}}
的形式去写
- 只有一个根标签
- 标签必须闭合
- 标签首字母
(1) 若小写字母开头,则将该标签转为html中同名元素,若html中无该标签对应的同名元素,则报错
(2) 若大写字母开头,react就去渲染对应的组件,若组件没有定义,则报错
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
| const myId = 'aTgUiGu' const myData = 'HeLlo,rEaCt'
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> )
const VDOM = ( <div> <h1>前端js框架列表</h1> <ul> { data.map((item,index)=>{ return <li key={index}>{item}</li> }) } </ul> </div> )
ReactDOM.render(VDOM,document.getElementById('test'))
|
组件
函数式组件
执行了ReactDOM.render(<MyComponent/>...
之后,发生了什么?
- React解析组件标签,找到了MyComponent组件。
- 发现组件是使用函数定义的,随后调用该函数,将返回的虚拟DOM转为真实DOM,随后呈现在页面中。
1 2 3 4 5 6 7
| //1.创建函数式组件 function MyComponent(){ console.log(this); //此处的this是undefined,因为babel编译后开启了严格模式 return <h2>我是用函数定义的组件(适用于【简单组件】的定义)</h2> } //2.渲染组件到页面 ReactDOM.render(<MyComponent/>,document.getElementById('test'))
|
类式组件
执行了ReactDOM.render(<MyComponent/>...
之后,发生了什么?
- React解析组件标签,找到了MyComponent组件。
- 发现组件是使用类定义的,随后new出该类的实例,并通过该实例调用到原型上的render方法。
- 将render返回的虚拟DOM转为真实DOM,随后呈现在页面中。
1 2 3 4 5 6 7 8 9 10 11 12
| //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'))
|
组件实例三大属性
state
理解:
state是组件对象最重要的属性, 值是对象(可以包含多个key-value的组合)
组件被称为”状态机”, 通过更新组件的state来更新对应的页面显示(重新渲染组件)
this指向问题:
首先需要明确的内容:
- 构造器内的this指向实例对象
- render内的this也指向实例对象
- class内开启局部严格模式,类其余方法内的this为undefined
现在关注render函数:
1
| return <h1 onClick={this.changeWeather}>今天天气很{isHot ? '炎热' : '凉爽'},{wind}</h1>
|
如果没有上方的bind语句,在点击时以普通函数的方式触发changeWeather
故changeWeather内的this指向window,又因为局部的严格模式,所以this指向undefined,访问它的state就会报错
所以要使用bind,将weather实例对象绑定给changeWeather方法,使得this指向正确
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33
| class Weather extends React.Component{ //构造器调用1次 constructor(props){ super(props) //初始化状态 this.state = {isHot:false,wind:'微风'} //解决changeWeather中this指向问题 //将changeWeather方法绑定到实例对象上,以后在调用该方法时,其中的this指向实例对象 this.changeWeather = this.changeWeather.bind(this) }
//render调用1+n次(1表示初始化 n是状态更新的次数) render(){ const {isHot,wind} = this.state return <h1 onClick={this.changeWeather}>今天天气很{isHot ? '炎热' : '凉爽'},{wind}</h1> }
//changeWeather调用几次? ———— 点几次调几次 changeWeather(){ //changeWeather放在哪里? ———— Weather的原型对象上,供实例使用 //由于changeWeather是作为onClick的回调,所以不是通过实例调用的,是直接调用
console.log('changeWeather'); //获取原来的isHot值 const isHot = this.state.isHot //注意:状态必须通过setState进行更新,且更新是一种合并,不是替换。 this.setState({isHot:!isHot}) console.log(this);
//注意:状态(state)不可直接更改 //this.state.isHot = !isHot //这是错误的写法 } }
|
总结:
组件中render方法中的this为组件实例对象
组件自定义的方法中this为undefined,如何解决?
- 强制绑定this: 通过函数对象的bind()
- 箭头函数
状态数据,不能直接修改或更新