简体   繁体   中英

Component local state not updating with react custom hooks

I'm just starting to use react hooks and I'm having some issues when using custom hooks. It's probably lack of understanding but here's what I'm attempting

My Custom hook:

import React, { useState } from "react"

export const useValidateContent = initState => {
    const[valid, setValid] = useState(initState)
    const[errorMsg, setErrorMsg] = useState(null)

    const validate = () => {
      // Update component state to test
      setValid(false)
      setErrorMsg('Some error found')
    }

    return [valid, validate, errorMsg]

}

My parent container which uses the custom hook:

import React, { useState, useEffect } from 'react'
import { useValidateContent } from './hooks/useValidateContent'


export default function ParentComp () {

    const [contentIsValid, validate, contentError] = useValidateContent(true)

    const initValidate = () => {
        // values before running validate
        console.log('valid', contentIsValid)
        console.log('error', contentError)
        validate()
        // values after running validate
        console.log('valid', contentIsValid)
        console.log('error', contentError)
    }

    return (
      <div>
        <button onclick={initValidate} />
      </div>
    )
}

What I expected to be consoled here was:

valid true
error null
valid false
error Some error found

Instead what I see is:

valid true
error null
valid true
error null

It seems like the hook is not updating the local state. Why is this? Even when I try to console those values inside the hook component I get the same thing. I cannot figure out why this is. Am I using custom hooks wrong?

Updating state with hooks is asynchronous just like setState in a class component is, and since the state is not mutated contentIsValid and contentError will still refer to the stale old state and not the new state.

If you render your state variables you will see that your code works as expected.

 const { useState } = React; const useValidateContent = initState => { const [valid, setValid] = useState(initState); const [errorMsg, setErrorMsg] = useState(""); const validate = () => { setValid(false); setErrorMsg("Some error found"); }; return [valid, validate, errorMsg]; }; function ParentComp() { const [contentIsValid, validate, contentError] = useValidateContent(true); const initValidate = () => { // values before running validate console.log("valid", contentIsValid); console.log("error", contentError); validate(); // values after running validate console.log("valid", contentIsValid); console.log("error", contentError); }; return ( <div> <button onClick={initValidate}>initValidate</button> contentIsValid: {contentIsValid.toString()}, contentError: {contentError} </div> ); } ReactDOM.render(<ParentComp />, document.getElementById("root"));
 <script src="https://unpkg.com/react@16/umd/react.development.js"></script> <script src="https://unpkg.com/react-dom@16/umd/react-dom.development.js"></script> <div id="root"></div>

valid state is set when you called validate() function and since the custom hook return valid state value to the component you use it at, you can directly use valid state.

The problem is, when you called validate() and "valid" got its state changed, but our component needs to tell when valid gets a value assign render our component. So in react functional compoennts we can simply put "valid" as a dependency for useEffect. then whenever valid gets state it will call a re render for our component.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM