Reputation: 1
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
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
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
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