最近我的项目用了 umi3+react17+antd pro5
我的项目中遇到的 useState 的坑
1.useState 不适宜简单对象的更改
因为 useState 不能像 setState 那样进行合并更新,当应用 useState 第二个参数进行数据更新的时候,必须传入一个残缺的构造,而不仅仅只是扭转的那一部分。
2.useState 异步回调的问题
当应用 usestate 对数据进行更新,并不能立即获取到最新的数据。
const [name, setName] = useState('dx');
const handleTest = () => {console.log(name) // dx
setName('dx1')
console.log(name) // dx
}
解决方案
一、配合 useEffect 应用
const [name, setName] = useState('dx');
const handleTest = () => {console.log(name) //dx
setName('dx1')
console.log(name)//dx
}
useEffect(() => {console.log(name) //dx1
},[name])
二、创立一个新的变量保留最新的数据
const [name, setName] = useState('dx');
const handleTest = () => {console.log(name) //dx
const newName = "dx1"
setName(newName)
console.log(newName) //dx1
}
3. 依据 hook 的规定,应用 useState 的地位有限度
- 仅顶层调用 Hook:不能在循环,条件,嵌套函数等中调用 useState()。
- 在多个 useState()调用中,渲染之间的调用程序必须雷同。
- 仅从 React 函数调用 Hook: 必须仅在函数组件或自定义钩子外部调用 useState()。
4. 应用 useState,回调函数模式更改数据
const [a, setA] = useState({c:1})
/** oldA 为之前的 a,return 为设置的新值 */
setA((oldA) => {return {c: oldA.c + 1}
})
5.useState 存入的值只是该值的援用(援用类型)
const textObj = {name:'dx'}
const [useState1, setUseState1] = useState(textObj)
const [useState2, setUseState2] = useState(textObj)
/** usestate 的操作不要放在函数的最外层,这里只是简略的代码展现,你能够将 set 操作放在某个函数外面 */
setUseState1((oldUseState1) => {
oldUseState1.age = 18
return {...oldUseState1}
})
useEffect(() => {
/** 扭转一个会导致两个都扭转, 深浅拷贝的问题 */
console.log(useState1) // {name: "dx", age: 18}
console.log(useState2) // {name: "dx", age: 18}
},[useState1])
解决的计划
const textObj = {name:'dx'}
const [useState1, setUseState1] = useState(textObj)
const [useState2, setUseState2] = useState(JSON.parse(JSON.stringify(textObj)))
/** usestate 的操作不要放在函数的最外层,这里只是简略的代码展现,你能够将 set 操作放在某个函数外面 */
setUseState1((oldUseState1) => {
oldUseState1.age = 18
return {...oldUseState1}
})
useEffect(() => {
/** 扭转一个会导致两个都扭转, 深浅拷贝的问题 */
console.log(useState1) // {name: "dx", age: 18}
console.log(useState2) // {name: "dx"}
},[useState1])
6.useState,如果保留援用数据,useEffect 检测不到变动?
const textObj = {name:'dx'}
const [useState1, setUseState1] = useState(textObj)
/** usestate 的操作不要放在函数的最外层,这里只是简略的代码展现,你能够将 set 操作放在某个函数外面 */
setUseState1((oldUseState1) => {
oldUseState1.age = 18
return oldUseState1
}
useEffect(() => {console.log(useState1)
},[useState1])
// 后果是没有任何反馈
解决办法
const textObj = {name:'dx'}
const [useState1, setUseState1] = useState(textObj)
/** usestate 的操作不要放在函数的最外层,这里只是简略的代码展现,你能够将 set 操作放在某个函数外面 */
setUseState1((oldUseState1) => {
oldUseState1.age = 18
/** 返回一个新的对象,useEffectc 能力检测失去 */
return {...oldUseState1}
}
useEffect(() => {console.log(useState1) // {name: "dx", age: 18}
},[useState1])
7.useState 无奈保留一个函数
你是否尝试着将函数的援用作为一个变量保留到 useState 中去呢?
比方:
const testFunciton1 = () => {console.log({name: 'dx',age: '18'})
}
/** usestate 保留函数测试 */
const [stateFunction, setstateFunction] = useState<() => void>(testFunciton1);
useEffect(() => {console.log(stateFunction)// {name: 'dx', age: 18}
}, [stateFunction])
代码中从未调用过 testFunciton1,后果 testFunciton1 却被执行了
useEffect 打印进去的却是一个 undefined。
略微改变一下代码,再测试
const testFunciton1 = () => {console.log({name: 'dx',age: '18'})
return {
name: 'yx',
age: '17'
}
}
/** usestate 保留函数测试 */
const [stateFunction, setstateFunction] = useState<() => void>(testFunciton1);
useEffect(() => {console.log(stateFunction)// {name: 'dx', age: 18} // {name: 'yx', age: 17}
}, [stateFunction])
很显著,在 useState 中,函数会主动调用,并且保留函数返回的值,而不能保留函数自身。
解决的计划
应用 useState 不能保留函数,那么能够应用 useCallback 这个 hook。
/** useCallback, 应用参数与 useEffect 统一 */
const testFunction = useCallback(() => {
// useCallback 返回的函数在 useCallbak 中构建
const testFunciton1 = () => {console.log({ name: 'dx', age: '18'});
return {
name: 'yx',
age: '17',
};
};
return testFunciton1;
}, []);
useEffect(() => {console.log(testFunction());// 打印的是函数
}, [testFunction]);