【问题标题】:useState() bug - state value different from initial valueuseState() 错误 - 状态值与初始值不同
【发布时间】:2020-01-14 09:53:46
【问题描述】:

我有一个组件使用useState() 来处理其浮动标签的状态,如下所示:

const FloatingLabelInput = props => {
  const {
    value = ''
  } = props

  const [floatingLabel, toggleFloatingLabel] = useState(value !== '')

我有一系列这些组件,您希望initialFloatingLabelfloatingLabel 始终相同,但它们不适合其中的一些!我可以通过记录值来查看:

const initialFloatingLabel = value !== ''
console.log(initialFloatingLabel) // false
const [floatingLabel, toggleFloatingLabel] = useState(initialFloatingLabel)
console.log(floatingLabel) // true???

这是一个一致的结果。这怎么可能?

为什么value 可以不同于以下示例中的initialValue?这是一种竞争条件吗?

const [value, setValue] = useState(initialValue)

更多详情here

更新

这个 (as suggested) 解决了这个问题:

useEffect(() => setFloatingLabel(initialFloatingLabel), [initialFloatingLabel])

...但它会创建另一个:如果我专注于一个字段,输入一些内容然后将其删除,直到该值为空字符串,它将“取消浮动”标签,就像这样(标签应该是浮动的) :

我不打算一直根据输入value 更新floatingLabel 状态; initialFloatingLabel 的值仅用于指示切换的初始值,我会在 handleBlurhandleChange 事件上切换它,如下所示:

const handleFocus = e => {
  toggleFloatingLabel(true)
}

const handleBlur = e => {
  if (value === '') {
    toggleFloatingLabel(false)
  }
}

这种方法错了吗?

更新

我一直在寻找新的解决方案,但始终存在一个持续存在的问题,我会说这是 Formik 的问题 - 在完全从 Formik 的 @ 计算值之前,它似乎最初是从它的 render props 函数渲染我的所有输入组件987654340@.

例如:

我添加了另一个本地状态,我在 handleFocushandleBlur 上进行了更新:

const [isFocused, setFocused] = useState(false)

所以我可以这样做以防止在输入为空但聚焦时取消浮动标签:

useEffect(() => {
    const shouldFloat = value !== '' && !isFocused
    setFloatLabel(shouldFloat)
  }, [value])

我仍然会这样做以防止预先填充的字段在标签上的动画从非浮动变为浮动(我为此使用react-spring):

const [floatLabel, setFloatLabel] = useState(value !== '')

但我仍然会在我在此线程开头指出的那些特定字段上获得标签上的动画(从“浮动”到“非浮动”),这些字段没有预先填充。

根据 cmets 的建议,我完全放弃了 floatingLabel 本地状态,只保留了 isFocused 本地状态。太好了,我真的不需要,标签动画只能有这个:

const animatedProps = useSpring({
    transform: isFocused || value !== '' ? 'translate3d(0,-13px,0) scale(0.66)' : 'translate3d(0,0px,0) scale(1)',
    config: {
      tension: 350,
    },
  })

代码现在看起来更干净了,但我仍然在标签上显示不应该的动画(对于我在开头提到的那些相同的特定值),因为 value !== '' 等于 true 对于 一些模糊的原因在第一次渲染,然后再次false

在设置字段的初始值时,我是否对 Formik 做错了什么?

【问题讨论】:

  • 你能创建一个codepen来重现这个吗?
  • floatingLabel 派生自props.value;为什么你需要状态呢? const floatingLabel = props.value !== ''; 就足够了吗?

标签: reactjs react-hooks formik


【解决方案1】:

initialFloatingLabel 更改时,您可以使用useEffect 更新您的状态。

const initialFloatingLabel = value !== ''
const [floatingLabel, setFloatingLabel] = useState(initialFloatingLabel)

// calling the callback when initialFloatingLabel change
useEffect(() => setFloatingLabel(initialFloatingLabel), [initialFloatingLabel])

...

您的问题看起来像支柱钻孔问题。也许您应该将floatingLabel 存储在context 中。

// floatingLabelContext.js
import { createContext } from 'react'

export default createContext({})

// top three component
...
import { Provider as FloatingLabelProvider } from '../foo/bar/floatingLabelContext'

const Container = () => {
  const [floatingLabel, setFloatingLabel] = useState(false)
  return (
    <FloatingLabelProvider value={{ setFloatingLabel, floatingLabel }}>
      <SomeChild />
    </FloatingLabel>
  )
}

//  FloatingLabelInput.js
import FloatingLabelContext from '../foo/bar/floatingLabelContext'

const FloatingLabelInput = () => {
  const { setFloatingLabel, floatingLabel } = useContext(FloatingLabelContext)

  ...
}

这样,您只需使用上下文来更改或读取组件三中所需的 floatingLabel 值。

【讨论】:

  • 他在问为什么它们不同,而不是如何使它们相同!
  • useEffect() 解决了这个问题!但不幸的是,它产生了另一个问题,这也不是我打算使用该组件的方式,但也许我的方法有缺陷?请看我的更新!
猜你喜欢
  • 1970-01-01
  • 2021-09-11
  • 1970-01-01
  • 2019-08-18
  • 2021-09-22
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-06-14
相关资源
最近更新 更多