React是什么?
官方文档上解释是:React 是一个声明式,高效且灵活的用于构建用户界面的 JavaScript 库。使用 React 可以将一些简短、独立的代码片段组合成复杂的 UI 界面,这些代码片段被称作“组件”。
一个简单的react组件是怎么样的?
在上一节我们创造一个react项目,现在我们创建的一个叫做HelloWorld.js的react组件,在App.js里引入该组件就行,引入代码为使用es6的import去引入,具体代码如下:
import HelloWorld from './components/HelloWorld
具体解释是import是es6语法,HelloWorld被引入的组件名,'./components/HelloWorld’在项目中组件的地址。
下面是我们创建的一个叫做HelloWorld.js的react组件。代码1
import React, { Component } from 'react'; // 引入react和react的Component
export default class HellWorld extends Component { // 输出一个默认名字为HellWorld的类并继承了react的Component类
render() {
return (
<div>HellWorld</div>
)
}
}
上面代码其实代价于下面代码:
代码2
import React, { Component } from 'react'; // 引入react和react的Component
class HellWorld extends Component { //写一个HellWorld的类并继承了react的Component类
render() {
return (
<div>HellWorld</div>
)
}
}
export default HellWorld // 输出一个默认名字为HellWorld的类
由此可清晰可见一个react的组件有三部分组成。一、引入react;二、书写一个类并继承react的Component类;三、输出默认类名。
其中二书写一个类,里面有一个render函数,这个函数里面可以写HTML的dom结构和js这里叫做jsx语法。
jsx的原理,是将dom解析为一个dom对象,上面代码解析后会变成如下所示代码:
代码3
import React, { Component } from 'react'
export default class HellWorld extends Component {
render() {
return (
// <div>HellWorld</div>
React.createElement(
"div",
null,//这里写一个该dom包含的属性对象,比如{className:'bg-red',id:'app'},这表示这个div有class类为bg-red,id为app
"HellWorld"
)
)
}
}
也就是说代码1和代码2、代码3渲染出来的效果是完全一样的。
重点:
1)render函数里面必须是一个dom标签包裹住其他dom标签,也就是说最外层的dom标签不能有兄弟dom.如果写两个并列的dom编辑器和浏览器都会报错如下图所示:
2)render函数里return返回里要写js需要{}包裹,代码如下:
import React, { Component } from 'react'
import './index.css'
export default class HelloWorld extends Component {
render() {
let a= 'HelloWorld---a'
return (
<div>{a}</div>
)
}
}
运行结果如下:
react中如何修改样式
修改样式有如下两种。一种是设置style,style里传递的是一个对象;一种是设置className(注意不是class,设置成class会报错),引入具有相应class类的css文件即可。具体表现形式和代码如下:
import React, { Component } from 'react'
import './index.css' // 引入css文件
export default class HelloWorld extends Component {
render() {
let a= 'HelloWorld---a'
let stylea = {color:'blue'}
return (
<div>
{/* 1、直接以对象的形式给style */}
<div style={{color:'red'}}>HelloWorld</div>
{/*2、 以对象变量的形式给style */}
<div style={stylea}>HelloWorld</div>
{/* 3、直接写class的css类名 */}
<div className='bg-red'>{a}</div>
{/* 4、利用js的正则表达式动态的写class的css类名 */}
<div className={1+1>0?'bg-blue':''}>HelloWorld----b</div>
</div>
)
}
}
在项目中利用js的正则表达式去动态的改变项目里组件的样式是非常常见的。
react中状态怎么写?
第一种是直接在render外面写一个state对象,具体示例如下所示:
import React, { Component } from 'react'
export default class HelloWroldState extends Component {
state={
hello:'HelloWroldState-----hello'
}
render() {
return (
<div>
<div>HelloWroldState</div>
<div>{this.state.hello}</div>
</div>
)
}
}
代码运行结果如下图所示:
第二种写法就是在render外面写一个constructor构造函数,请千万注意里面要加个super()不然会报错,具体代码如下:
import React, { Component } from 'react'
export default class HelloWroldState extends Component {
// state={
// hello:'HelloWroldState-----hello'
// }
constructor(){
super()
this.state={
helloBlue:'HelloWroldState-----helloBlue'
}
}
render() {
return (
<div>
<div>HelloWroldState</div>
{/* <div style={{color:'red'}}>{this.state.hello}</div> */}
<div style={{backgroundColor:'blue'}}>{this.state.helloBlue}</div>
</div>
)
}
}
一般正式项目开发时一般以第二种写法为主,可是做为小垃圾的我们也得认识人家第一种写法,不能说别人写错了,不然就有点贻笑大方了。
**注意:**这里的this是指向class组件。
React的state怎么变化?
做为一个js老手顾名思义一个js对象的值改变,我们传统的方法直接赋值改变就行了,比如:
let object={a:'3',b:'4'};
object.a = 8
console.log(object) // {a:8,b:4}
直接就修改了,但是React的state却是不能这样变化,它依赖于React的特性,需要调用setState方法。具体代码如下:
import React, { Component } from 'react'
export default class HelloWroldState extends Component {
// state={
// hello:'HelloWroldState-----hello'
// }
constructor(){
super()
this.state={
helloBlue:'HelloWroldState-----helloBlue',
num:0
}
}
render() {
return (
<div>
<div>HelloWroldState</div>
{/* <div style={{color:'red'}}>{this.state.hello}</div> */}
<div style={{backgroundColor:'blue'}}>{this.state.helloBlue}</div>
<h1>{this.state.num}</h1>
<button onClick={this.click}>加一</button>
</div>
)
}
click=()=>{
this.setState({
num:this.state.num+1
})
}
}
结果如下所示:
setState方法的注意事项
1、在同步方法中,setState方法是合并执行的,即它只会运行一次,而且还是异步的,异步更新状态,异步更新真实dom。具体看代码,代码如下:
import React, { Component } from 'react'
export default class HelloWroldState extends Component {
// state={
// hello:'HelloWroldState-----hello'
// }
constructor(){
super()
this.state={
helloBlue:'HelloWroldState-----helloBlue',
num:0
}
}
render() {
return (
<div>
<div>HelloWroldState</div>
{/* <div style={{color:'red'}}>{this.state.hello}</div> */}
<div style={{backgroundColor:'blue'}}>{this.state.helloBlue}</div>
<h1>{this.state.num}</h1>
<button onClick={this.click}>加一</button>
</div>
)
}
click=()=>{
this.setState({
num:this.state.num+1
})
console.log('log1',this.state.num)
this.setState({
num:this.state.num+1
})
console.log('log2',this.state.num)
this.setState({
num:this.state.num+1
})
console.log('log3',this.state.num)
}
}
结果如下图所示:
由上图可以看出来num从0变到1,说明click方法里面的setState方法都合并了只执行了一次,但是三个console打印里面都是0,说明setState是异步的nun打印出来没变,但是页面上是有变化的说明setState是起了作用的。
2、在原生方法和setTimeout异步方法中,setState同步执行,状态同步更新,dom同步渲染.
3、setState的第二个参数是回调函数,可以取到变化值。
import React, { Component } from 'react'
export default class HelloWroldState extends Component {
// state={
// hello:'HelloWroldState-----hello'
// }
constructor(){
super()
this.state={
helloBlue:'HelloWroldState-----helloBlue',
num:0
}
}
render() {
return (
<div>
<div>HelloWroldState</div>
{/* <div style={{color:'red'}}>{this.state.hello}</div> */}
<div style={{backgroundColor:'blue'}}>{this.state.helloBlue}</div>
<h1>{this.state.num}</h1>
<button onClick={this.click}>加一</button>
</div>
)
}
click=()=>{
this.setState({
num:this.state.num+1
},()=>{
console.log('log000',this.state.num)
})
this.setState({
num:this.state.num+1
},()=>{
console.log('log001',this.state.num)
})
this.setState({
num:this.state.num+1
},()=>{
console.log('log002',this.state.num)
})
console.log('log1',this.state.num)
this.setState({
num:this.state.num+1
})
console.log('log2',this.state.num)
this.setState({
num:this.state.num+1
})
console.log('log3',this.state.num)
}
}
执行结果
4、setState函数调用一次会引发render函数重新渲染。没有state的变化则render不会重新渲染。这点在于组件里数据渲染变化的应用中很是重要
5、react中要特别注意this的指向问题,所以为了规避这个问题,一般都会选择箭头函数,因为箭头函数的this是指向他的非箭头函数的方法的,所以会一直指向到class,从而不会发生错误。
闲话
隔了很久重新捡起,感觉还是有点小吃力,祝大家温故而知新。