I have converted class component to functional component and I am stuck. I tried everything to pass the value (user id and password) to Redux.
When I console log ‘inputs’, I see [object Object] but, login and password show exact name and value.
How can I pass name and value to inputs in this case?
function Login(props) {
const classes = useStyles();
const [inputs, setInputs] = useState({
// you can login with email or username
login: '',
password: '',
keepLogged: false
function handleChange(e) {
e.preventDefault();
const { name, value } = e.target;
setInputs({ ...inputs, [name]: value });
console.log(`${inputs}`)
const loginUser = () => {
const { requestSignIn } = props;
requestSignIn({ inputs });
console.log(`inputs; ${inputs}`)
return (
<Grid container component='main' className={classes.root}>
<CssBaseline />
<Grid item xs={false} sm={4} md={7} className={classes.image} />
<Grid item xs={12} sm={8} md={5} component={Paper} elevation={6} square>
<div className={classes.paper}>
<img src={Logo} style={{ width: 300 }} />
<Typography component='h1' variant='h5'>
Sign in
</Typography>
<form className={classes.form} noValidate>
<TextField
variant='outlined'
margin='normal'
required
fullWidth
id='email'
label='Email Address'
value={inputs.login}
onChange={e => handleChange(e)}
name='login'
autoComplete='email'
autoFocus
<TextField
variant='outlined'
margin='normal'
required
fullWidth
name='password'
label='Password'
value={inputs.password}
onChange={e => handleChange(e)}
type='password'
id='password'
autoComplete='current-password'
<FormControlLabel
control={<Checkbox value='remember' color='primary' />}
label='Remember me'
<Button
type='submit'
fullWidth
variant='contained'
color='primary'
value='Log In'
className={classes.submit}
onClick={() => loginUser()}
Sign In 🙂
</Button>
<Grid container>
<Grid item xs>
<Link href='#' variant='body2'>
Forgot password?
</Link>
</Grid>
<Grid item>
variant='body2'
onClick={() => history.push('/registration')}
{"Don't have an account? Sign Up"}
</Link>
</Grid>
</Grid>
<Box mt={5}>
</form>
</Grid>
</Grid>
const mapDispatchToProps = dispatch => ({
requestSignIn: data => dispatch(requestSignIn(data))
export default connect(null, mapDispatchToProps)(Login);
The dispatch is a side effect, so use React.useEffect.
useEffect runs every time the component rerenders (ie every time the state changes).
[Following is not essential, but makes things simpler]: for simplicity you ideally do not want the state to be a single object. So you define like
const [login, setLogin] = useState("");
const [password, setPassword] = useState("");
const [keepLoggedIn, setKeepLoggedIn] = useState(false);
Anyway, I would advise always doing that rather than using objects unless strictly necessary. Keep things as flat as possible, avoid nesting things inside objects if you can avoid it. If you do need complex state, think about using useReducer instead of individual useState values (though this will make you’re code a little more complex).
After that, you also need a value that you can set if the user has clicked submit so that the component rerenders if the user tries to log in. At that point, you can dispatch the other values from the state.
const [isLoggingIn, setIsLoggingIn] = useState(false);
You can write handlers for all of these, but as none of the logic is complex, you can just put them inline
value={login}
onChange={e => setLogin(e.target.value)}
value={password}
onChange={e => setPassword(e.target.value)}
value={keepLoggedIn}
onChange={e => setKeepLoggedIn(!keepLoggedIn)}
Submit button doesn’t have a value – it’s triggering a side effect (dispatching to the store)
<button type="submit" onClick={() => setIsLoggingIn(true)}>
Now your state updates, but it doesn’t actually do anything. Make it do something:
useEffect(() => {
console.log(`Login: ${login}, Password: ${password}, Keep logged in: ${keepLoggedIn}`);
// Only dispatch is `isLoggingIn` is true
if (isLoggingIn) {
props.requestSignIn({ name: login, password });
// Once we've dispatched, not logging in any more,
// so set `isLoggingIn` back to false
setIsLoggingIn(false);
// Note the list of values that your useEffect hook should
// react to here -- this is essential to avoid bugs
}, [login, password, keepLoggedIn, isLoggingIn]);
Also, you don’t need that connect call. react-redux provides hooks, and they’re much easier and cleaner
import { useDispatch } from "react-redux";
// ... some code
function Login(props) {
const dispatch = useDispatch();
// ...some code
useEffect(() => {
console.log(`Login: ${login}, Password: ${password}, Keep logged in: ${keepLoggedIn}`);
if (isLoggingIn) {
dispatch(requestSignIn({ name: login, password }));
// Once we've dispatched, not logging in any more,
// so set `isLoggingIn` back to false
setIsLoggingIn(false);
}, [login, password, keepLoggedIn, isLoggingIn]);
// ...rest of code
Here is a full example – I don’t know the API for the UI library you’ve used, so I’ve just used plain HTML elements instead
stackblitz.com
Note that it clears the form after dispatching by accident – I haven’t build any logic to handle that, and it does need to be handled, the pretend reducer is the thing that’s doing it afaics, so it should work ok with your actual reducer. Anyway, you can look in the console and see the state updating every time you type something, then the pretend dispatch going to the store
Hi! First of all, thank you for your answer. I am super lost. But, I will read carefully and follow the post.
I was using class component and switching to functional in order to use Material-UI theme (i dunno why it doesn’t work on class component) and also taking it as a learning experience.
gihihikikiaihi:
I was using class component and switching to functional in order to use Material-UI theme (i dunno why it doesn’t work on class component) and also taking it as a learning experience.
Yep, I get that – it’ll be a bit hard to grok at first, but it should be easier in the long run. useEffect is the important thing to understand when you’re moving to hooks (it’s what replaces basically all the lifecycle methods), and unfortunately it’s also the thing that’s kinda hardest to grok
No! It is just me. I read that useEffect was the replacement for componentDidMount() and willMount() such thing. I did not know if it could have used this way.
There are always something to learn!
I am sorry to bother ya again. But, this is the class component that I wanted to convert to functional. I tried to apply to your solution and again I am stuck. So, keepLogged does nothing. I think it was there for future reference.
I changed [inputs, setInputs] to 3 different inputs. However, it has not converted to requestSignIn 
class Login extends Component {
state = {
login: '',
password: '',
keepLogged: false
changeValue = event => {
event.preventDefault();
const value = event.target.value;
const name = event.target.name;
this.setState({
[name]: value
checkedValue = event => {
console.log(event.target.checked, event.target.name);
const value = event.target.checked;
const name = event.target.name;
this.setState({
[name]: value
loginUser = () => {
const { login, password } = this.state;
const { requestSignIn } = this.props;
requestSignIn({ login, password });
render() {
const { login, password } = this.state;
return (
<LoginWrapper>
<Container style={{ border: '1px solid #757575', padding: '5%' }}>
<Col style={{ textAlign: 'right', marginRight: '25px' }}>
<LoginHeader>Log In to Your Account</LoginHeader>
<LoginForm>
<FormControl
name='login'
type='text'
placeholder='Username/Email'
value={login}
onChange={this.changeValue}
style={{ marginBottom: '10px' }}
<FormControl
name='password'
type='password'
placeholder='Password'
value={password}
onChange={this.changeValue}
style={{ marginBottom: '10px' }}
<Button
variant='info'
value='Log In'
onClick={() => this.loginUser()}
Log In
</Button>
</LoginForm>
<LoginBottom
onClick={() => history.push('/registration')}
style={{ marginTop: '30px' }}
Need an account?{' '}
<Link style={{ color: '#007bff' }}>Sign Up</Link>
</LoginBottom>
</Container>
</LoginWrapper>
const mapDispatchToProps = dispatch => ({
requestSignIn: data => dispatch(requestSignIn(data))
export default connect(null, mapDispatchToProps)(Login);
function Login() {
const classes = useStyles();
const [login, setLogin] = useState('')
const [password, setPassword] = useState('')
const [keepLogged, setKeepLogged] = useState(false)
function handleChangeLogin(e) {
e.preventDefault();
const { name, value } = e.target;
setLogin({ ...login, [name]: value });
console.log(`${login}`)
function handleChangePass(e) {
e.preventDefault();
const { name, value } = e.target;
setPassword({ ...password, [name]: value });
console.log(`${password}`)
const loginUser = () => {
const { login, password } = this.state;
const { requestSignIn } = this.props;
requestSignIn({ login, password });
console.log(`inputs; ${password}`)
return (
<Grid container component='main' className={classes.root}>
<CssBaseline />
<Grid item xs={false} sm={4} md={7} className={classes.image} />
<Grid item xs={12} sm={8} md={5} component={Paper} elevation={6} square>
<div className={classes.paper}>
<img src={Logo} style={{ width: 300 }} />
<Typography component='h1' variant='h5'>
Sign in
</Typography>
<form className={classes.form} noValidate>
<TextField
variant='outlined'
margin='normal'
required
fullWidth
id='email'
label='Email Address'
value={login}
onChange={e => handleChangeLogin(e)}
name='login'
autoComplete='email'
autoFocus
<TextField
variant='outlined'
margin='normal'
required
fullWidth
name='password'
label='Password'
value={password}
onChange={e => handleChangePass(e)}
type='password'
id='password'
autoComplete='current-password'
<FormControlLabel
control={<Checkbox value='remember' color='primary' />}
label='Remember me'
<Button
type='submit'
fullWidth
variant='contained'
color='primary'
value='Log In'
className={classes.submit}
onClick={() => loginUser()}
Sign In 🙂
</Button>
<Grid container>
<Grid item xs>
<Link href='#' variant='body2'>
Forgot password?
</Link>
</Grid>
<Grid item>
variant='body2'
onClick={() => history.push('/registration')}
{"Don't have an account? Sign Up"}
</Link>
</Grid>
</Grid>
<Box mt={5}>
</form>
</Grid>
</Grid>
const mapDispatchToProps = dispatch => ({
requestSignIn: data => dispatch(requestSignIn(data))
export default connect(null, mapDispatchToProps)(Login);