Search code examples
javascriptreactjsecmascript-6react-hooksusecallback

React functional component does not change as soon as value changes


I've made a react component for reset password page. After a reset token is sent to the user email, the reset page has three inputs: token, new password and confirm password. The latter two are hidden until a sha256 token is entered in the token field, upon which the password fields appear and the token field disappears. This used to work until I also forwarded a URL with the reset token in the reset URL. Thus I had to add the compShow() function in my useEffect() as well so as soon as the component is loaded it checks for the token and updates the token field, rendering it invisible. This works in the URL with reset token but the URL without the reset which is supposed to show only token field first and then hide token and show password fields does not work as intended now. The token field only disappears if I press an extra character after the token is entered( I use space). I figure it is because the first time I change the value of the placeholder state variable in the onChangedHandler function, compShow() does not get triggered. But when I add an extra character, the compShow function detects the change in the placeholder and executes its respective code.

Can someone tell me why does this happens and what should I do to get the intended result?

The code snippet is provided below

const [placeholder, setPlaceholder] = useState('')

const { onReleaseError, onError } = props

const compShow = useCallback(() => {
    if (validator.isHash(placeholder, 'sha256')) {
      setShowToken({ display: 'none' })
      setShow(style.show)
      setErrorType('red')
      onReleaseError()
    }
  }, [placeholder, onReleaseError])

  useEffect(() => {
    const path = new URL(document.location).pathname.split('/')[2] || null
    if (path) {
      setPlaceholder(path)
      compShow()
    } else {
      setErr(onError)
      if (onError) setErrorType('green')
    }
  }, [compShow, onError])

  const onChangeHandler = e => {
    setPlaceholder(e.target.value)
    compShow()
  }

Solution

  • Apparently the solution was much simpler. useCallback locks in the value it takes at the begining of a component render/ update. The placeholder defined at the beginning of the component is an empty string, hence it does not change while we call the compShow function. But as I take in an input which may or may not be placeholder but has the same value, compShow function takes the updated value of placeholder and functions as intended.

    const [placeholder, setPlaceholder] = useState('')
    const { onReleaseError, onError } = props
    
    const compShow = useCallback(
        val => {
          if (validator.isHash(val, 'sha256')) {
            setShowToken({ display: 'none' })
            setShow(style.show)
            setErrorType('red')
            onReleaseError()
          }
        },
        [onReleaseError]
      )
    
      useEffect(() => {
        const path = new URL(document.location).pathname.split('/')[2] || null
        if (path) {
          setPlaceholder(path)
          compShow(path)
        } else {
          setErr(onError)
          if (onError) setErrorType('green')
        }
      }, [compShow, onError])
    
      const onChangeHandler = e => {
        setPlaceholder(e.target.value)
        compShow(e.target.value)
      }