Search code examples
reactjsreact-hooksuse-effectuse-reducer

Where to place dispatch function for useReducer and why?


I'm new to React and I'm currently learning about useReducer. I've created a simple login feature that verifies if the user inputted email includes '@' and the password length is greater than 5. If these two conditions are met, I want my program to display an alert with success or fail message when pressing on the submit button.

What I'm curious about is that the application displays "Success" on submit when I add dispatch({type: 'isCredValid')} in useEffect(commented out in the code below), but the application displays "fail" when I add the dispatch({type: 'isCredValid'}) in the onSubmit handler without using useEffect. I was expecting the application to display "Success" when adding the dispatch({type: 'isCredValid')} in the onSubmit handler without the help of useEffect. Why is it not displaying "Success"? And why does my application display "Success" when the dispatch function is in the useEffect?

Reducer function :

const credReducer = (state, action) => {
    switch(action.type) {
        case 'email' :
            return {...state, email: action.value, isEmailValid: action.value.includes('@')};
        case 'password' :
            return {...state, password: action.value, isPasswordValid: action.value.length > 5 ? true : false};
        case 'isCredValid' :
            return {...state, isCredValid: state.isEmailValid && state.isPasswordValid ? true : false};
        default :
            return state;
    }
}

Component and input handlers

const Login = () => {

    const [credentials, dispatch] = useReducer(credReducer, {
        email: '',
        password: '',
        isEmailValid: false,
        isPasswordValid: false,
        isCredValid: false
    })

    // useEffect(() => {
    //     dispatch({type: 'isCredValid'})
    // }, [credentials.isEmailValid, credentials.isPasswordValid])

    const handleSubmit = (e) => {
        e.preventDefault()
        dispatch({ type: "isCredValid" })

        if (credentials.isCredValid === true) {
            alert ("Success!")
        } else {
            alert ('failed')
        }
    }

    const handleEmail = (e) => {
        dispatch({ type: "email", value: e.target.value })
    }

    const handlePassword = (e) => {
        dispatch({ type: "password", value: e.target.value })
    }

  return (
    <Card className={classes.card}> 
        <h1> Login </h1>
        <form onSubmit={handleSubmit}>
            <label>Email</label>
            <input type="text" value={credentials.email} onChange={handleEmail}/>
            <label>Password</label>
            <input type="text" value={credentials.password} onChange={handlePassword}/>
            <button type="submit"> Submit </button>
        </form>

    </Card>
  )
}

Solution

  •  if (credentials.isCredValid === true) {
         alert ("Success!")
      } else {
         alert ('failed')
      }
    

    You are probably referring to above alert that you didn't immediately see "Success". That doesn't happen like that, just like with updating state, when you dispatch something, you will see the update on the next render.