Pete
Pete

Reputation: 3

Js react set value after onBlur causes users to have to click twice

I have a react form with an input button with an onBlur event on it. In the onblur function I set the value to an useState property. But if I use that the user has to click twice on the button next to it in order to get the focus of the button.. It seems that the page needs to progress the change in the useState one you click once on the button and the 2nd time it will do what is use to do:

const {useState} = React;

function App() {
    const [gridLine, setGridLine] = useState({
        hours: "",
    });

    const TopBanner = () => {

        const setHours = (event) => {

            setGridLine(prev => ({
                ...prev,
                hours: event.target.value
            }));
        }

        const addLine = e => {
            e.preventDefault();

            alert(`I am clicked, value = ${gridLine.hours}`);
        }        

        return (
            <div>
                <div className="form-control">
                    <label>Time Spend</label>
                    <input type="text" name="ticketTime" defaultValue={gridLine.hours}  
                        onBlur={setHours}
                        data-required="1" />
                </div>
                <div className="submit">
                    <a id="btnAddHours" href="#" className="btn" onClick={addLine}>Add</a>
                </div>
            </div>
        );
    }

    return (
        <TopBanner></TopBanner>
    )
}

const domContainer = document.querySelector('#like_button_container');
const root = ReactDOM.createRoot(mount);
root.render(<App/>);
<script crossorigin src="https://unpkg.com/react@18/umd/react.development.js"></script>
<script crossorigin src="https://unpkg.com/react-dom@18/umd/react-dom.development.js"></script>
<div id="mount"></div>

This a part of the code, but I have kept the main part that is causing the issue.

What can I do so that after onBlur the hours are set in gridLine and that an user does not have to click twice on the button.

(note the button is not the problem, I have the same issue with any other control on the page)

I have tried to use onChange, setFocus, but to no prevail.

Upvotes: 0

Views: 641

Answers (1)

Keith
Keith

Reputation: 24181

Your issue is that your putting the state with App, so every time you update the state, the whole App is getting re-rendered.

Simply moving the useState into the Component will solve this.

Unfortunately React's state is not meant to share between component to component, so if you need state information passing to App, don't use React.useState. The good news there are lots of multi-component state managers out there, Jotai is a really simple one -> https://jotai.org/

const {useState} = React;

function App() {

    const TopBanner = () => {
    
        const [gridLine, setGridLine] = useState({
          hours: "",
        });


        const setHours = (event) => {

            setGridLine(prev => ({
                ...prev,
                hours: event.target.value
            }));
        }

        const addLine = e => {
            e.preventDefault();

            alert(`I am clicked, value = ${gridLine.hours}`);
        }        

        return (
            <div>
                <div className="form-control">
                    <label>Time Spend</label>
                    <input type="text" name="ticketTime" 
                        defaultValue={gridLine.hours}  
                        onBlur={setHours}
                        data-required="1" />
                </div>
                <div className="submit">
                    <a id="btnAddHours" href="#" className="btn" onClick={addLine}>Add</a>
                </div>
            </div>
        );
    }

    return (
        <TopBanner></TopBanner>
    )
}

const domContainer = document.querySelector('#like_button_container');
const root = ReactDOM.createRoot(mount);
root.render(<App/>);
<script crossorigin src="https://unpkg.com/react@18/umd/react.development.js"></script>
<script crossorigin src="https://unpkg.com/react-dom@18/umd/react-dom.development.js"></script>
<div id="mount"></div>

Upvotes: 0

Related Questions