标签:render 概念 函数返回 利用 call 变化 mes vue timer
组件从概念上来看就像JS中的一个函数,它可以接收任意的输入值(称之为props),并返回一个需要在页面上展示的React元素。我们可以将UI切分成几个不同的,独立的,可复用的部分,进行单个部分即单个组件的构建,后面进行整合展示就可。
一、函数组件和类组件
组件的名称必须是大写开头,这样是为了在使用时可以和html标签区分开来。函数组件的创建是定义一个首字母大写的函数,这个函数返回jsx,jsx它是依赖React,所以组件内部必须要引入React。在使用组件时,里面写的行内属性都是自定义属性,我们在函数的内部通过props进行接收。组件需要返回一个并且只能返回一个React根元素,所以有多个组件时要用空标签或者是div标签进行包裹。
import React from ‘react‘;
import ReactDOM from ‘react-dom‘;
let str = ‘我是天空里的一片云‘
//普通函数
function Div(props) {
// 在组件上使用的行内属性都是自定义属性
return <h3>我的名字是:{props.name},年龄是:{props.age}</h3>
}
//箭头函数
let H3 = (props) => {
// 在html标签上使用的行内属性都是react规定的
return <h3 style={{color:props.style}}>{str}</h3>
}
ReactDOM.render(<>
<Div name="davina" age={20} />
<H3 style="ligthblue"></H3>
</>,
document.querySelector(‘#root‘))
同函数组件一样,类组件首字母也需大写,它继承了React的Component这个类有自己的this和生命周期。如下所示,我们创建了一个Welcome类,它里面必须要有render函数,会默认调用render方法,并且返回一个能被渲染的结果,这个返回结果就是虚拟DOM,即React元素。在return的React元素有多个时,要有标签进行包裹,不然会报错。
类组件也是先进行属性对象的收集,像下面的<Welcome {...data} />中{ name: ‘davina‘, age: 20 }就会作为Welcome组件的props属性对象进行传入。在传入后,会把属性对象传递给构造函数,并得到类的实例。在props初始化完成后,this.props变量就保存了props属性对象的地址,后面我们在调用render函数时,可以通过this.props访问数据。组件的props一般来源于默认属性或者是由父组件的state内部数据传递而来,基于react是单向数据流,所以在组件内部props是只读的不能修改。虽然可以通过修改父组件的state方式进行修改,但是不建议。它仍旧遵循的是props不可更改这一规则。
import React from ‘react‘;
import ReactDOM from ‘react-dom‘;
//Wlecome类继承了React.Component这个类
class Welcome extends React.Component {
//在class声明的类中有一个规定写了constructor就必须要写super()
// constructor(props) {
// super()它相当于是call继承,它其实就是继承的那个类的函数体本身,在这里指的就是React.Component
// super(props) //将props挂载在this上
// }
render() {
//可以通过this.props调用到属性
console.log( this.props);
return <h3>我的名字是:{this.props.name},年龄是:{this.props.age}</h3>
}
}
let data = { name: ‘davina‘, age: 20 }
ReactDOM.render(<Welcome {...data} />, document.querySelector(‘#root‘))
二、state
react中的组件只有两大数据源,一个属性props,二是状态state。上文中我们说了props,下面我们来看一下state。每个组件都有自己独立的内部数据,在类组件中state内部数据是放在构造函数中作为私有属性来定义的。
当我们要修改state时,因为react不像vue那样对数据进行监听并且在数据变化时刷新视图,而是数据变化通过重新调用render方法,来更新视图。所以我们需要调用render函数。babel提供了一个可以自动调用render函数的APIsetState(),即我们可以利用setState可以触发视图的更新,也就是让render函数执行。换句话说,当我们调用了setState这个函数时,react会更新组件的state,并且重新调用render方法,再把render方法渲染的最新内容显示到页面上。react在更新组件的state时它并不会马上修改state,而是把它放到一个事件队列里面,当数据更数完后才会将新的state提取出来合并到旧的state中,所以只需要传入新的state需要修改的部分就可。随后再进行组件的更新操作。
import React from ‘react‘;
import ReactDOM from ‘react-dom‘;
class App extends React.Component {
constructor(props) {
super(props)
//在构造函数中这是唯一可以给this.state赋初始值的地方
// 当前组件的私有属性
this.state = {
name: ‘davina‘,
date: new Date().toLocaleTimeString()
}
}
//当组件渲染完成后会触发componentDidMount钩子函数
componentDidMount() {
//改变状态的唯一方式就是setState
this.$timer = setInterval(() => {
this.setState({ date: new Date().toLocaleTimeString() })
}, 1000);
}
render() {
//解构赋值
let { name, date } = this.state;
return <>
<h3>我的名字是:{name}</h3>
<h4> 现在的时间为:{date}</h4>
</>
}
}
ReactDOM.render(<App />, document.getElementById(‘root‘))
setState函数它其实是一个异步函数,更新数据时绝大多数情况下是异步操作。但是在原生事件或者是计时器中setTimeout/setInterval这种react无法掌握的API时,会直接去更新state,可以立即得到最新的state它是一个同步的操作。
因为在项目中使用setState时绝大多数是异步更新,我们可以使用以下方法强制让react不用异步操作。setState函数式用法即将一个回调函数传入setState方法中或者可以在setState更新后进行的逻辑封装到一个函数中作为第二个参数传给setState即setState(updater,[callback])还可以把需要在setState更新后进行逻辑放在生命周期的hook函数中通过以上的三种方法我们可以实现同步的操作。
import React from ‘react‘;
import ReactDOM from ‘react-dom‘;
class App extends React.Component {
//state的另一种写法,可以不用写constructor
state = { count: 100, val: 20 }
add() {
this.setState(
{ count: this.state.count + 1 }, function () {
console.log(this.state.count);//这时数据更新完就立即触发,它是一个同步操作
}
)
console.log(this.state.count);//它是一个异步操作,得到的不是立即加1的值,它是旧的state
}
componentDidMount() {
//同步执行
this.timer = setInterval(() => {
this.setState({ val: this.state.val - 1 })
console.log(this.state.val);
}, 1000);
}
render() {
let { count, val } = this.state;
return <>
<button onClick={this.add.bind(this)}>add</button>
<h3>count的当前值是:{count}</h3>
<h4>val的当前值是:{val}</h4>
</>
}
}
ReactDOM.render(<App />, document.getElementById(‘root‘))
标签:render 概念 函数返回 利用 call 变化 mes vue timer
原文地址:https://www.cnblogs.com/davina123/p/13615162.html