繁体   English   中英

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

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

我最近开始在 React 项目中使用 Redux-Saga,因为它对我来说是新的,我想了解它是如何工作的。 我也开始使用 Formik,因为它在 React 应用程序中管理表单似乎已经使 Redux-Form 黯然失色。 现在,我理解 Dan Abramov 的基本原理,即“将 React 用于临时状态,这对全局应用程序无关紧要,并且不会以复杂的方式发生变化。”

但这似乎与 Redux-Saga 文档中列出的SOMETHING_REQUESTED -> apiCall -> SOMETHING_SUCCESS or SOMETHING_FAILURE模式不一致。 例如,如果我有一个表单在 onSubmit 上分派一些动作,一个传奇“采取”来执行异步请求,我没有看到一种方法可以让我的表单了解该请求的状态而不将其存储在 Redux 状态中的某处(我们想要避免的确切反模式)。 我可以想象的一种替代方法是在表单提交处理程序中执行请求,而不是将其委托给 saga,但这让我想知道,Redux-Saga 有什么意义?

请帮助填补我理解中的空白。

编辑:仅供参考,redux-saga repo 上的这个 GitHub 问题似乎与我的问题最相关,虽然那里写了很多,但似乎没有达成一致的最佳实践。

这个reddit线程也涉及这个话题,但是和线程的OP类似,我想知道为什么他在Redux Promise Listener中找到的解决方案没有被更广泛地采用?

我可以想象的一种替代方法是在表单提交处理程序中执行请求,而不是将其委托给 saga

正确,这足以处理文件上传。 redux-saga用于此操作将是一种过度杀伤。 我相信人们应该努力为给定的任务选择正确的工具。

但这让我想知道, redux-Saga什么意义?

redux-saga视为使异步操作同步的“进程管理器”。 有时代码流是预料之中的,不会有任何意外。 尽管有时并非如此,因为副作用(例如 API 调用)会导致控制反转。 因此,导致我们何时会得到回应的意外和不确定性。

我没有看到一种方法可以让我的表单了解该请求的状态而不将其存储在 Redux 状态中的某处

在这个演示中,我将redux-sagaFormik一起使用,以控制两件事:

  1. 用于将文件POST到端点的 API 调用。
  2. uploading标志,用于在用户等待文件上传时控制 UI

redux只处理uploading ,而其余​​的值由formikredux-saga处理,这有助于提供更好的用户体验(用户在 UI 中有一个uploading指示器)和开发人员体验(我们是通过yield响应来控制 saga 中的执行流程)。

我所做的是将 formik 操作发送到 saga 并根据 saga API 调用响应处理表单操作。

这是我的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;

这是我处理 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);
  };

这是我的传奇功能:

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