- 作者:老汪软件技巧
- 发表时间:2024-10-31 11:00
- 浏览量:
Hook
React的Hook就是一些React提供的内置函数,这些函数可以让函数组件拥有和类组件一样的组件状态(state)以及模拟类组件的生命周期函数。但是不要什么业务都使用Hook,要在合适的时候使用Hook,否则会造成性能问题。(能不用的时候就不要用,当遇到性能不好优化的时候,自然会想到使用Hook)
useState和类组件的this.state一样,都是用来管理组件状态的。在React的Hook没出来之前,函数组件也叫做Functional Stateless Component(FSC:功能无状态的组件),这是因为函数组件本身的函数体就是render,每次重新渲染时就会重新运行整个函数并生成新的函数作用域。所以同一个函数组件是不能够共用状态的。 而类组件是重新运行render函数,组件状态并不会重新创建。
useState允许函数组件将自己的状态持久化并存储在React运行时的某个地方,这样在函数组件每次重新渲染的时候都可以从这个地方拿到该状态,而且当该状态被更新的时候,组件也会重渲染。
state的创建和更新
useState基本使用
// App.js
// 函数组件
import { useState } from 'react'
import Son from './son.js';
function App() {
let msg = useState("I Am Gloria");
console.log(msg);
return (
<>
<h1>App 组件h1>
<Son>Son>
>
)
}
export default App;
useState函数返回值是一个数组,数组中第一个元素是当前state的最新值,第二个元素是一个方法,该方法是用来更新state的函数,函数传入的值就是要修改的数据,而且调用该函数会刷新页面,并重新取值使用的state,将state修改为最新的数据。
// App.js
import { useState } from 'react'
import Son from './son.js';
function App() {
let msg = useState("I Am Gloria");
let change = () => {
msg[1]('I Am Gloria World Tour');
};
let look = function () {
console.log(msg);
}
return (
<>
<h1>App 组件h1>
<h5>{msg[0]}h5>
<button onClick={change}>changebutton>
<button onClick={look}>lookbutton>
<Son>Son>
>
)
}
export default App;
常用的是通过解构赋值来创建state,效果同理。
// 函数组件
import { useState } from 'react'
import Son from './son.js';
function App() {
let [msg, setMsg] = useState("I Am Gloria");
let change = () => {
setMsg('I Am Gloria World Tour');
};
let look = function () {
console.log(msg, 'msg');
console.log(setMsg, 'setMsg')
}
return (
<>
<h1>App 组件h1>
<h5>{msg}h5>
<button onClick={change}>changebutton>
<button onClick={look}>lookbutton>
<Son>Son>
>
)
}
export default App;
msg和setMsg这两个变量名是自定义的,msg可用于组件内部使用创建的state数据,setMsg函数用于修改state,当修改后,所有使用过msg的地方都会重新取值(调用render刷新页面)。 一个函数组件中可以用多个useState。
useState注意事项useState可以传入函数
const [ state , dispatch ] = useState(initData)
比如:
// 函数组件
import { useState } from "react"
function App(props) {
const propsCount = props.count || 0;
let [count, setCount] = useState(propsCount)
return (
<>
<p>{count}p>
<button onClick={() => { setCount(count++) }}>addbutton>
>
)
}
export default App;
const propsCount = props.count || 0 是不合理的,因为每次重新渲染函数组件时都会执行这行代码,而这行代码的意图是在初始化的时候执行,所以需要在useState的参数里放入一个函数。传入的函数仅在初始渲染时执行一次,以获得初始状态。
useState更新数据
在使用useState的dispatch更新state的时候,会浅比较两次state,发现state相同,不会开启更新任务。对于引用数据如果两次 state 指向了相同的引用地址,就会认为 state 相等,所以不会发生视图更新了。
// 函数组件
import { useState } from 'react'
function App() {
let [obj, setObj] = useState({ name: "G.E.M.", title: "I am gloria world tour" });
let change = () => {
obj.name='golden stars';
setObj(obj);
};
let look = function () {
console.log(obj);
}
return (
<>
<p>{obj.name}p>
<p>{obj.title}p>
<button onClick={change}>changebutton>
<button onClick={look}>lookbutton>
>
)
}
export default App;
当状态是一个引用数据时,可以使用展开运算符浅拷贝引用数据,重新申请一个内存空间,然后更新部分状态。
import { useState } from 'react'
function App() {
let [obj, setObj] = useState({ name: "G.E.M.", title: "I am gloria world tour" });
let change = () => {
obj.name='golden stars';
// {...obj}大括号在js语法中就是创建对象的直接量,此处就是传入了一个装有响应式对象的所有成员的新对象
setObj({...obj});
};
let look = function () {
console.log(obj);
}
return (
<>
<p>{obj.name}p>
<p>{obj.title}p>
<button onClick={change}>changebutton>
<button onClick={look}>lookbutton>
>
)
}
export default App;
useState返回数组中第二个元素用于修改状态的函数是全量替代。全量替代就是传入的数据会把原来的数据全部替换。 而类组件的浅归并是传入的数据原来有就会更新,原来没有的数据就会创建该数据。
import { useState } from 'react'
function App() {
let [obj, setObj] = useState({ name: "G.E.M.", title: "I am gloria world tour" });
let change = () => {
obj = setObj({ msg: 'golden stars', name: "Gloria" });
};
let look = function () {
console.log(obj);
}
return (
<>
<p>{obj.name}p>
<p>{obj.title}p>
<button onClick={change}>changebutton>
<button onClick={look}>lookbutton>
>
)
}
export default App;
传入对象会把原来的覆盖,传入的对象中没有title属性,取属性值就是undefined,undefined不会在页面渲染。
useState是异步操作
useState返回的修改状态的dispatch函数没有回调函数。无论是useState还是类组件的this.setState都是异步调用的,也就是说每次组件调用完之后都不能立即拿到最新的state值。
为了解决这个问题,类组件的this.setState中第一个参数是要修改的数据,第二个参数是一个回调函数,用来获取到最新的state值:
this.setState(newState, state => { console.log( state)})
函数组件的setState函数不存在这么一个可以拿到最新state的回调函数,不过我们可以使用useEffect来实现相同的效果。