How to run setSubmitting() outside the submit handler?

爱⌒轻易说出口 提交于 2019-12-09 09:28:16

问题


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 ?


回答1:


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



回答2:


If the Formik component could accept isSubmitting as prop, then it could be implemented much more elegantly. Right now it doesn't (see source). This would be a great feature request to the Formik team.




回答3:


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


来源:https://stackoverflow.com/questions/53344755/how-to-run-setsubmitting-outside-the-submit-handler

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!