简体   繁体   English

如何使用 Formik 和 Redux-Saga 处理表单状态

[英]How to handle form state with Formik and Redux-Saga

I recently started using Redux-Saga in a React project since it was new to me and I wanted to learn how it works.我最近开始在 React 项目中使用 Redux-Saga,因为它对我来说是新的,我想了解它是如何工作的。 I also started using Formik since it appears to have eclipsed Redux-Form in popularity for managing forms in React applications.我也开始使用 Formik,因为它在 React 应用程序中管理表单似乎已经使 Redux-Form 黯然失色。 Now, I understand Dan Abramov's rationale to "use React for ephemeral state that doesn't matter to the app globally and doesn't mutate in complex ways."现在,我理解 Dan Abramov 的基本原理,即“将 React 用于临时状态,这对全局应用程序无关紧要,并且不会以复杂的方式发生变化。”

But this seems at odds with the pattern of SOMETHING_REQUESTED -> apiCall -> SOMETHING_SUCCESS or SOMETHING_FAILURE laid out in Redux-Saga's documentation.但这似乎与 Redux-Saga 文档中列出的SOMETHING_REQUESTED -> apiCall -> SOMETHING_SUCCESS or SOMETHING_FAILURE模式不一致。 For example, if I have a form that dispatches some action onSubmit that a saga "takes" to perform the asynchronous request, I don't see a way to keep my form apprised of the status of that request without storing it in Redux state somewhere (the exact antipattern we want to avoid).例如,如果我有一个表单在 onSubmit 上分派一些动作,一个传奇“采取”来执行异步请求,我没有看到一种方法可以让我的表单了解该请求的状态而不将其存储在 Redux 状态中的某处(我们想要避免的确切反模式)。 One alternative I could imagine is to perform the request within the form submission handler and not delegate it to a saga, but then that makes me wonder, what is the point of Redux-Saga?我可以想象的一种替代方法是在表单提交处理程序中执行请求,而不是将其委托给 saga,但这让我想知道,Redux-Saga 有什么意义?

Please help fill in the gaps in my understanding.请帮助填补我理解中的空白。

Edit: FYI this GitHub issue on the redux-saga repo seems most pertinent to my question, and while there is much written there it doesn't seem to arrive at an agreed best practice.编辑:仅供参考,redux-saga repo 上的这个 GitHub 问题似乎与我的问题最相关,虽然那里写了很多,但似乎没有达成一致的最佳实践。

This reddit thread also deals with this topic, but similar to the thread's OP, I wonder why the solution he found in Redux Promise Listener is not more widely adopted? 这个reddit线程也涉及这个话题,但是和线程的OP类似,我想知道为什么他在Redux Promise Listener中找到的解决方案没有被更广泛地采用?

One alternative I could imagine is to perform the request within the form submission handler and not delegate it to a saga我可以想象的一种替代方法是在表单提交处理程序中执行请求,而不是将其委托给 saga

Correct, this is enough for handling file upload.正确,这足以处理文件上传。 Using redux-saga for this operation would be an over-kill.redux-saga用于此操作将是一种过度杀伤。 I believe that one should strive to pick the correct tool for a given task.我相信人们应该努力为给定的任务选择正确的工具。

but then that makes me wonder, what is the point of redux-Saga ?但这让我想知道, redux-Saga什么意义?

Consider redux-saga as a "process manager" for making async operation as sync.redux-saga视为使异步操作同步的“进程管理器”。 Sometimes the flow of code is expected and there wont be any surprises.有时代码流是预料之中的,不会有任何意外。 Although sometimes it doesn't so, since there is inversion of control caused by side effects (eg API calls).尽管有时并非如此,因为副作用(例如 API 调用)会导致控制反转。 Therefore, causing surprises and uncertainty about when we will get our response.因此,导致我们何时会得到回应的意外和不确定性。

I don't see a way to keep my form apprised of the status of that request without storing it in Redux state somewhere我没有看到一种方法可以让我的表单了解该请求的状态而不将其存储在 Redux 状态中的某处

In this Demo I'm using redux-saga together with Formik in order to control 2 things:在这个演示中,我将redux-sagaFormik一起使用,以控制两件事:

  1. API call for POST ing a file to an endpoint.用于将文件POST到端点的 API 调用。
  2. uploading flag for controlling the UI while the user is waiting for the file to be uploaded uploading标志,用于在用户等待文件上传时控制 UI

redux handles only uploading , whereas the rest of the values are handled by formik and redux-saga that helps to provide a better user-experience (the user have an uploading indicator for what is happening in the UI) and developer-experience (we are controlling the flow of executionin the saga by yield ing the response). redux只处理uploading ,而其余​​的值由formikredux-saga处理,这有助于提供更好的用户体验(用户在 UI 中有一个uploading指示器)和开发人员体验(我们是通过yield响应来控制 saga 中的执行流程)。

What I have done is to send formik actions to saga and handle the form actions based on saga API call response.我所做的是将 formik 操作发送到 saga 并根据 saga API 调用响应处理表单操作。

This is my formik form representational component:这是我的formik表单表示组件:

import React from "react";
import { ErrorMessage, Field, Form, Formik } from "formik";
import * as Yup from "yup";
import { Button, Col, FormGroup } from "reactstrap";

const RefundForm = (props) => {
  return (
    <Formik
      initialValues={{
        bank: "",
        amount: "",
      }}
      validationSchema={Yup.object({
        // availableEmoney: Yup.string().required("Required"),
        // availableLimit: Yup.string().required("Required"),
        bank: Yup.string().required("Required"),
        amount: Yup.string().required("Required"),
      })}
      onSubmit={props.handleSubmitMethod}
    >
      {(formikProps) => (
        <Form onSubmit={formikProps.handleSubmit}>
          <div className="form-row">
            <Col lg={8} xl={8}>
              <FormGroup>
                <label>Bank Name & Account Number</label>
                <Field
                  as="select"
                  name="bank"
                  className="form-control"
                >
                  <option value="">Select a bank</option>
                  {props.banks.map((bank) => {
                    return (
                      <option value={bank.id} key={bank.id}>
                        {`${bank.bank_name} (${bank.bank_account_number})`}
                      </option>
                    );
                  })}
                </Field>
                <ErrorMessage
                  name="bank"
                  component="div"
                  className="text-danger"
                />
              </FormGroup>
            </Col>

            <Col lg={4} xl={4}>
              <FormGroup>
                <label>Amount</label>
                <Field name="amount" type="text" className="form-control" />
                <ErrorMessage
                  name="amount"
                  component="div"
                  className="text-danger"
                />
              </FormGroup>
            </Col>
          </div>
          <div className="form-row mt-3 text-right">
            <Col>
              <Button
                className="primary-color"
                type="submit"
                disabled={!formikProps.dirty || formikProps.isSubmitting}
              >
                Submit
              </Button>
            </Col>
          </div>
        </Form>
      )}
    </Formik>
  );
};


export default RefundForm;

This is my function that handles the formik form submit:这是我处理 formik 表单提交的函数:

  const handleRefundFormSubmit = (values, actions) => {
    //values: form values. actions: formikActions 

    dispatch(
      createRefund({
        data: {
          amount: values.amount,
          distributor_bank_id: values.bank,
        },
        formikActions: actions, // sending formik actions to the saga
      })
    );
    actions.setSubmitting(false);
  };

This is my saga function:这是我的传奇功能:

function* createNewRefund(action) {
  try {
    const response = yield call(
      postDataWithAuth,
      REFUND_CREATE,
      action.payload.data
    );
    yield put(createRefundSuccessful(response.message));
// Call the formik resetForm() function if the response is success so that the 
// the form is cleared
    yield put(action.payload.formikActions.resetForm());
  } catch (error) {
    yield put(createRefundFailed(error.response.data));
  }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM