18-useState响应式变量
大约 3 分钟
代码也是有后台的 xswl🤣
state 和 props 类似,都是一种存储属性的方式,但是不同点在于 state 只属于当前组件,其他组件无法访问。并且 state 是可变的,当其发生变化后组件会自动重新渲染,以使变化在页面中呈现。
state
在 React 中,当组件渲染完毕后,再修改组件中的变量,不会使组件重新渲染
要使得组件可以收到变量的影响,必须在变量修改后对组件进行重新渲染 这里我们就需要一个特殊变量,当这个变量被修改使,组件会自动重新渲染
state 相当于一个变量,
只是这个变量在 React 中进行了注册, React 会监控这个变量的变化,当 state 发生变化时,会自动触发组件的重新渲染 使得我们的修改可以在页面中呈现出来 在函数组件中,我们需要通过 钩子函数 ,获取 state
标准写法
使用钩子 useState() 来创建 state
import {useState} from "react";
它需要一个值作为参数,这个值就是 state 的初始值
该函数会返回一个数组
- 数组中第一个元素,是初始值 - 初始值只用来显示数据,直接修改不会触发组件的重新渲染
- 数组中的第二个元素,是一个函数,通常会命名为 setXxx - 这个函数用来修改 state,调用其修改 state 后会触发组件的重新渲染,并且使用函数中的值作为新的 state 值
const [counter, setCounter] = useState(1);
const addHandler = () => {
setCounter(counter + 1); // 将counter值修改为2
};
return <div className={'app'}>
<h1>{counter}</h1>
<button onClick={addHandler}>+</button>
</div>;
等价于
const result = useState(1);
// counter 是初值
let counter = result[0];
// setCounter 调用该函数,重新渲染视图
let setCounter = result[1];
setCounter
其实就是 重新调用 render
函数,又因为 diff
算法,如果元素不发生改变,不会调用 render
注意事项
- 当 state 的值是一个对象时,修改时是使用新的对象去替换已有对象。修改对象的属性不会触发 diff 算法,
- 用浅拷贝,可以生成新对象,再修改新对象的属性值
const newObj = Object.assign({}, Obj); newObj.age=18.setObj(newObj)
setuser({...user,age:19})
,基础好的话就可以这样
- 用浅拷贝,可以生成新对象,再修改新对象的属性值
- 当通过 setState 去修改一个 state 时,并不表示修改当前的 state 它修改的是组件下一次渲染时 state 值
const counter = 1;
counter 是常量,也不能修改的
- setState()会触发组件的重新渲染,它是异步的。
- 在异步队列,等待主线程计算完成,再渲染。所以当调用 setState()需要用旧 state 的值时,一定要注意有可能出现计算错误的情况
- 为了避免这种情况,可以通过为 setState()传递回调函数的形式来修改 state 值
const addHandler = () => {
setTimeout(() => {
// setCounter(counter + 1); // 将counter值修改为2
setCounter((prevCounter)=>{
/*
* setState()中回调函数的返回值将会成为新的state值
* 回调函数执行时,React会将最新的state值作为参数传递
* */
return prevCounter + 1;
});
// setCounter(prevState => prevState + 1);
}, 1000);
- setState 中的回调函数是异步回调,将会把当前同步函数执行一遍,再执行回调,因此获得的是最新的值