Home > database >  React state won't update from within a useCallback
React state won't update from within a useCallback

Time:11-05

I am using the following code to render a Material UI AutoComplete field with options retrieved from an API. I would like to prevent re-rendering of the input field but the chosen country is used as a prop for the Country component which should be updated onChange. set_alpha3Code doesn't seem to update the state from within useCallback. How do I get around that?

let AC = memo(AutocompleteCountries)

function Show(props: {})
{
    let [alpha3Code_, set_alpha3Code_] = useState<string>('gbr');

    let onChange = useCallback((alpha3Code) => {
        console.log(alpha3Code_);
        set_alpha3Code_(alpha3Code);
    }, []);

    return (
        <div>
            <AC onChange={onChange}/>
            {alpha3Code_ ? <Country cca3_={alpha3Code_}/> : null}
        </div>
    )
}

CodePudding user response:

Two things jump out about that code:

  • onChange without value
  • Stale state

onChange without value

In the normal case, if you specify onChange with an input control, you have to specify value to tell the control what the current (updated) value is. The documentation for Material-UI's Autocomplete definitely suggests you need both:

Controlled states

The component has two states that can be controlled:

  1. the "value" state with the value/onChange props combination. This state represents the value selected by the user, for instance when pressing Enter.

The same thing with a standard input prevents the input from ever changing. I haven't used the Material-UI Autocomplete, but I suspect it's similar.

Stale state

Your code is updating the value of alpha3Code_ (if onChange is called with a new value), but the console.log in that code looks at at an old one:

let onChange = useCallback((alpha3Code) => {
    console.log(alpha3Code_);       // <−−− Uses the *first* `alpha3Code_` only
    set_alpha3Code_(alpha3Code);
}, []);
// ^^−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−− Because you haven't included
//                                          `alpha3Code_` in these dependencies

But even though that console.log shows you outdeated information, the rest of the code is fine and will work. It will re-render the AC with the updated code.

If you want to see the alpha3Code_ used for rendering, put a breakpoint on the return and look at it in the debugger (or move the console.log outside the onChange handler to above the return).

CodePudding user response:

Thank you. Apologies for the question. The problem was within the useEffect dependencies of the Country component.

  • Related