关于javascript:react使用hookuseState的坑

53次阅读

共计 3333 个字符,预计需要花费 9 分钟才能阅读完成。

最近我的项目用了 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]);

正文完
 0