state
页面数据定义:用于在当前页面需要使用的数据定义。
与props的区别: props是由父组件传给子组件的属性传值。不可改变,只可以使用,而state是可以通过setState方法来进行改值,并且state的改变会引起render方法的触发,页面会进行重新渲染,所以通常我们会在声明周期中或者事件中对其进行操作。
//在类组件中的使用方法
// state = {
// name: 'zhangsan',
// age: 16
// }
constructor () {
super() //如果需要在构造器中设置state,那么就必需要用该命令。它是和extends配套使用的,它在这里表示父类的构造函数,用来新建父类的 this 对象super()相当于Parent.prototype.constructor.call(this)
this.state = {
name: 'zhangsan',
age: 16
}
}
addAge() {
this.setState({
age: ++this.state.age
})
}
subAge() {
this.setState({
age: --this.state.age
})
}
render() {
return (
<div>
类组件
<h1> {this.state.name} </h1>
<h1> {this.state.age} </h1>
<button onClick={this.addAge.bind(this)}>增加年龄</button>
<button onClick={this.subAge.bind(this)}>减少年龄</button>
</div>
)
}
//函数组件由于没有this所以数据定义方式也不同。
import React,{ useState } from 'react'
export default function Login() {
const [name, setName] = useState('lisi')
const [age, setAge] = useState(18)
const addAge = () => {
setAge(age + 1)
}
const subAge = () => {
setAge(age - 1)
}
return (
<div>
函数组件
<h1> {name} </h1>
<h1> {age} </h1>
<button onClick={addAge}>增加年龄</button>
<button onClick={subAge}>减少年龄</button>
</div>
)
}
值得注意的是this.setState()方法是一个异步函数,通常,第一个参数为一个对象,而第二个参数则为一个回调函数,在回调函数中会取到设置的新值,而在方法外面是不能马上获取到新设的值。如果想要将其修改为一个同步的话,我们可以使用一个setTimeOut()或者使用promise进行封装。
addAge() {
this.setState({
age: this.state.age + 1
},() => {
console.log(this.state.age)
})
console.log(this.state.age)
}
可以看出执行顺序实现执行同步代码,后执行异步。
在进行setTimeOut过后
addAge() {
setTimeout(() => {
this.setState({
age: this.state.age + 1
},() => {
console.log(this.state.age)
})
console.log(this.state.age)
},0)
}
这样就可以实现同步了。
原理:主要是利用了js运行机制,为了解决单线程运行的缺陷,将任务分为了宏任务和微任务
1.同步和异步任务分别进入不同的执行"场所",同步的进入主线程,异步的进入Event Table并注册函数
2.当指定的事情完成时,Event Table会将这个函数移入Event Queue。
3.主线程内的任务执行完毕为空,会去Event Queue读取对应的函数,进入主线程执行。
4.上述过程会不断重复,也就是常说的Event Loop(事件循环)。
而定时器是一个宏任务,在运行是会先执行setTimeOut,当主线程任务执行完,setState入场,执行回调函数,在异步方法结束过后,又会执行setTimeOut里面的同步代码。
页面获取节点
类组件获取方法
//方法一:在DOM标签上通过ref属性命名,然后,在挂载后声明周期中用setState方法进行赋值,这样的方法获取到的是一个标签。
componentDidMount() {
this.setState({
node: this.refs.node
},() => {
console.log(this.state.node)
})
}
<button ref='node' onClick={this.subAge.bind(this)}>减少年龄</button>
//方法2:通过createRef()方法来获取。
state = {
name: 'zhangsan',
age: 16,
node: '',
node1: createRef() //创建节点的方法
}
componentDidMount() {
this.setState({
node: this.refs.node
},() => {
console.log(this.state.node)
console.log(this.state.node1) // 获取到的是一个组件对象,拥有许多的方法,可以调用
})
}
//ref的数据绑定
<button ref={this.state.node1} onClick={this.addAge.bind(this)}>增加年龄</button>
函数组件获取方法
const node = useRef() //useRef()是一个异步方法
console.log(node) //undefine
useEffect(() => {
console.log(node)
},[node])
//通过使用useRef()来获取DOM节点,与createRef()类似。
<button ref={node} onClick={addAge}>增加年龄</button>
生命周期
有哪些生命周期
组件将要挂载时触发的函数:componentWillMount
组件挂载完成时触发的函数:componentDidMount
是否要更新数据时触发的函数:shouldComponentUpdate
将要更新数据时触发的函数:componentWillUpdate
数据更新完成时触发的函数:componentDidUpdate
组件将要销毁时触发的函数:componentWillUnmount
父组件中改变了props传值时触发的函数:componentWillReceiveProps
componentWillMount
在渲染前调用
组件还没有渲染完成,DOM还没挂载,组件还没有进入render
componentDidMount
在第一次渲染结束后调用
在这里已经进行了render挂载,组件第一次渲染完成,dom也完成了挂载,在这里我们可以发送ajax,修改state初始值,当调用了setState方法后会重新调用render方法,可以重新渲染,由于setState的这个特性,所以在render中我们不能使用该方法,否者会造成递归死循环。
shouldComponentUpdate
返回一个布尔值。在组件接收到新的props或者state时被调用。在初始化时或者使用forceUpdate时不被调用。 可以在你确认不需要更新组件时使用。
nextProps是父组件传给子组件的值,nextState是数据更新之后值,这两个值可以在这个函数中获取到。第二步当确认更新数据之后componentWillUpdate将要更新数据,第三步依旧是render,数据发生改变render重新进行了渲染。第四步是componentDidUpdate数据更新完成。
shouldComponentUpdate(nextProps, nextState){
if(nextProps.content !== this.props.content){
return true
}
else{
return false
}
}
componentWillReceiveProps
在组件接收到一个新的 prop (更新后)时被调用。这个方法在初始化render时不会被调用。
componentWillUpdate
更新之前调用
componentDidUpdate
更新之后会被立即调用。首次渲染不会执行此方法。当组件更新后,可以在此处对DOM进行操作,如果使用this.setState()方法,需要加上限制条件,不然会造成死循环
componentWillUnmount
写在之前,通常在这里我们会释放大数据对象、setTimeout。
类组件钩子函数
useEffect()
它与类组件的componentDidMount、shouldComponentUpdate这个生命周期类似,如果传递了第二个参数,在数据进行改变的时候,只有当被监听的数据发生变化才会执行这个方法,否则不会执行.
useEffect( () =>{
.........
},[props])
useMemo()
它类似于vue的computed的方法,会进行返回一个计算过后的值。,第二个参数为一个数组,里面包含了我们的依赖项,避免性能消耗,需要有一个返回值,return
let total = useMemo(() =>{
return amount * rate + amount
},[amount])