Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to run setSubmitting() outside the submit handler?

I'm trying to implement the approach described on https://www.youtube.com/watch?v=5gl3cCB_26M, where all Redux actions are just plain objects (as they were meant to be) and API calls are done by middlewares.

By doing this, the dispatched actions are no longer thunks and can't return a Promise. So I won't be able to use Formik's setSubmitting (to set the isSubmitting flag to false) inside the submit handler, like the code samples on Formik docs and other tutorials I've found.

I've solved the issue in a kinda ugly way, saving a reference of setSubmitting to run it later, inside componentDidUpdate:

import React, { Component } from 'react'
import { Redirect } from 'react-router-dom'

import LoginForm from 'path/to/LoginForm'
import validationSchema from 'path/to/LoginForm/validationSchema'

import { login } from 'path/to/actionCreators'

const initialValues = {
  email: '',
  password: '',
}

class LoginPage extends Component {
  componentDidUpdate() {
    const { auth } = this.props

    if (!auth.isProcessing && this.setSubmitting) {
      this.setSubmitting(false)
    }
  }

  onSubmit = (values, { setSubmitting }) => {
    const { dispatch } = this.props

    dispatch(login(values)))
    this.setSubmitting = setSubmitting
  }

  render() {
    const { auth } = this.props
    if (auth.user.uid) {
      return <Redirect push to="/" />
    }

    return (
      <div className="login-panel">
        <h1>Login</h1>

        <Formik
          initialValues={initialValues}
          onSubmit={this.onSubmit}
          render={LoginForm}
          validationSchema={validationSchema}
        />
      </div>
    )
  }
}

const mapStateToProps = state => ({
  auth: state.auth,
})

export default connect(mapStateToProps)(LoginPage)

How can I do it in a more "elegant" way ?

like image 425
Matheus Gomes Avatar asked Nov 16 '18 20:11

Matheus Gomes


People also ask

What is setSubmitting in Formik?

IMPORTANT: If onSubmit is async, then Formik will automatically set isSubmitting to false on your behalf once it has resolved. This means you do NOT need to call formikBag. setSubmitting(false) manually. However, if your onSubmit function is synchronous, then you need to call setSubmitting(false) on your own.

How do I get Formik values before submitting?

it is very simple just do console. log(formik. values) and you will get all the values without submitting it.


2 Answers

Another approach is by using ref on to the <Formik/> component (released in React 16.3)

class NewComponent extends Component {
  formikRef = React.createRef()

  render() {
    <Formik
      ref={this.formikRef}
      ..
      ..
    />
  }

  onButtonClick() {
    this.formikRef.current.setSubmitting(false);
  }
}
like image 198
yashhy Avatar answered Oct 05 '22 15:10

yashhy


You could implement callbacks. Just invoke an onSuccess or onError callback in your middleware and handle them in your component.

// component.js
class LoginPage extends Component {

  // ...

  onSubmit = (values, { setSubmitting }) => {
    const { dispatch } = this.props

    setSubmitting(true);
    dispatch(
      login(
        values,
        () => setSubmitting(false), // success callback to be invoked in middleware
        (message) => { // error handler invoked in middleware catch
          this._handleErrorMessage(message);
          setSubmitting(false);
        },
      )
    );
  }


}

// actions.js
function loginAction(payload, onSuccess, onError) {
  return {
    type: LOGIN,
    payload,
    onSuccess,
    onError,
  }
}

// middleware.js
function handleLogin(action) {
  const { payload, onSuccess, onError } = action;
  try {
    // login...
    onSuccess('hurray!');
  } catch(error) {
    const { message } = error;
    onError(message);
  }
}
like image 43
brettinternet Avatar answered Oct 05 '22 13:10

brettinternet