Home > database >  Where to place dispatch function for useReducer and why?
Where to place dispatch function for useReducer and why?

Time:07-22

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>
  )
}

CodePudding user response:

 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.

CodePudding user response:

This useEffect may work, but you're kind of abusing the dependency array here. You're not actually depending on credentials.isEmailValid or credentials.isPasswordValid. You should use these dependencies to decide which action to dispatch, and maybe that's your plan already.

The reason your handleSubmit doesn't seem to work, is what others point out. You won't be able to see the result until next render, so not inside the handleSubmit function.

    // 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')
        }
    }

To see the results, add another useEffect and trigger the alert from there:

useEffect(() => {
 if(credentials.isCredValid){
  alert('Success!')
 }
}, [credentials])
  • Related