mikkelele
mikkelele

Reputation: 1

React: setting state clears input on form submit

Beginner in React here...

I have made an API which I'm able to login with, like this:

// App.js
const [loginState, setLoginState] = useState([]);
    const handleLogin = async (e) => {
        e.preventDefault();
        const username = e.target.querySelector(".username");
        const password = e.target.querySelector(".password");
        const apiCall = await fetch(`${ROOT_URL}/api/login`, {
            method: "POST",
            headers: {
                Accept: 'application/json',
                'Content-Type': 'application/json'
            },
            body: JSON.stringify({
                username: username.value,
                password: password.value
            })
        });
        const response = await apiCall.json();
        setLoginState(response)

    };

My problem is that after each submit, the input values for username and password are cleared. How can prevent this? It seems like if I remove setLoginState the input values are kept, but how would I set the state ideally? My API returns some error messages if login is unsuccessful and I want to show those message to the user and still keep the username and password values in the input

My login component looks like this:

function Login(props) {
    const { handleLogin, loginState } = props;
    const { from } = "/" || props.location.state;

    if (!loginState.isLoggedIn) {
        return (
            <div>
                <h1>Login</h1>
                <form onSubmit={handleLogin} >
                    <input className="username" type="text" name="username" />
                    <input className="password" type="password" name="password" />

                    <button>Log in</button>
                </form>
            </div>
        );
    } else {
        return <Redirect to={from ? from : "/"}/>
    }
};

Upvotes: 0

Views: 218

Answers (3)

Yatin Gaikwad
Yatin Gaikwad

Reputation: 1200

In your App.js you can simply get the credentials from login Component

const handleLogin = async (credentials) => {

const apiCall = await fetch(`${ROOT_URL}/api/login`, {
    method: "POST",
    headers: {
        Accept: 'application/json',
        'Content-Type': 'application/json'
    },
    body: JSON.stringify(credentials)
});
const response = await apiCall.json();
};

and hadnle your submit here so that react will not refresh the page and use onchange in the form

function Login(props) {
const { handleLogin } = props;
const { from } = "/" || props.location.state;
const [username, setUsername] = useState('');
const [password, setPassword] = useState('');

const login = (e) => {
    e.preventDefault();
    handleLogin({ username: username, password: password })
  }

if (!loginState.isLoggedIn) {
    return (
        <div>
            <h1>Login</h1>
            <form onSubmit={login} >
                <input className="username" onChange={e => setUsername(e.target.value)}  type="text" name="username" />
                <input className="password" onChange={e => setPassword(e.target.value)} type="password" name="password" />

                <button>Log in</button>
            </form>
        </div>
    );
} else {
    return <Redirect to={from ? from : "/"}/>
}
};

Upvotes: 0

Vaibhav Nigam
Vaibhav Nigam

Reputation: 1487

Save values in state and render values in input fields from state itself. That is a controlled way of handling your inputs.

function Login(props) {
    const { handleLogin, loginState } = props;
    const { from } = "/" || props.location.state;
    const [username, setUsername] = React.useState('');
    const [password, setPassword] = React.useState('');

    if (!loginState.isLoggedIn) {
        return (
            <div>
                <h1>Login</h1>
                <form onSubmit={handleLogin} >
                    <input className="username" type="text" name="username"
                       value={username} 
                       onChange={evt => setUsername(evt.target.value)} />
                    <input className="password" type="password" name="password"
                       value={password}
                       onChange={evt => setPassword(evt.target.value)} />

                    <button>Log in</button>
                </form>
            </div>
        );
    } else {
        return <Redirect to={from ? from : "/"}/>
    }
};

Also, to get values from these input fields in your handleLogin function, simply access username and password variables.

const handleLogin = async (e) => {
        e.preventDefault();

        const apiCall = await fetch(`${ROOT_URL}/api/login`, {
            method: "POST",
            headers: {
                Accept: 'application/json',
                'Content-Type': 'application/json'
            },
            body: JSON.stringify({
                username,
                password
            })
        });
        const response = await apiCall.json();
        setLoginState(response)

    };

Upvotes: 0

Isidrok
Isidrok

Reputation: 2191

When you set the state React re-renders the component so input values are lost. If you need to keep values across re-renders you need to apply the concept of controlled inputs: make the input value depend on the component state and update the component state whenever the input changes, this will make your component set the input value that was stored in the state. Here is an example:

class ControlledInput extends React.Component {
    constructor(props) {
        super(props);
        this.state = {
            foo: 'Intitial value',
            check: true
        }
    }
    _updateFoo = (ev) => {
        const value = ev.target.value;
        this.setState({foo:value});
    }
    _updateCheck = (ev) => {
        const value = ev.target.checked;
        this.setState({check: value});
    }
    render() {
        return (
            <form>
                <input name="foo" type="text" value={this.state.foo} onChange= 
                {this._updateFoo} />
                <input name="check" type="checkbox" checked={this.state.check} 
                onChange={this._updateCheck}/>
            </form>
        );
    }
}

You can read more about it here: https://reactjs.org/docs/forms.html

Upvotes: 1

Related Questions