最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - Component local state not updating with react custom hooks - Stack Overflow

programmeradmin0浏览0评论

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 ponent 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 ponent I get the same thing. I cannot figure out why this is. Am I using custom hooks wrong?

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 ponent 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 ponent I get the same thing. I cannot figure out why this is. Am I using custom hooks wrong?

Share Improve this question asked Mar 28, 2019 at 19:17 bos570bos570 1,5234 gold badges25 silver badges49 bronze badges 5
  • 1 Updating state with hooks is asynchronous just like setState in a class ponent is, and since the state is not mutated contentIsValid and contentError will still refer to the stale old state and not the new state. – Tholle Commented Mar 28, 2019 at 19:27
  • @Tholle I don't quite follow. I though the setValid and setErrorMsg were supposed to mutate the state. – bos570 Commented Mar 28, 2019 at 19:31
  • It updates the state, but it doesn't update it in place like e.g. using the push method on an array does. The values will be updated in the next render. – Tholle Commented Mar 28, 2019 at 19:32
  • 1 @Tholle ahh, that makes so much more sense now. Thanks! – bos570 Commented Mar 28, 2019 at 19:35
  • Great! You're wele. – Tholle Commented Mar 28, 2019 at 19:36
Add a ment  | 

2 Answers 2

Reset to default 2

Updating state with hooks is asynchronous just like setState in a class ponent 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./react@16/umd/react.development.js"></script>
<script src="https://unpkg./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 ponent 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 ponent needs to tell when valid gets a value assign render our ponent. So in react functional poennts we can simply put "valid" as a dependency for useEffect. then whenever valid gets state it will call a re render for our ponent.

发布评论

评论列表(0)

  1. 暂无评论