【问题标题】:How to handle form state with Formik and Redux-Saga如何使用 Formik 和 Redux-Saga 处理表单状态
【发布时间】:2019-03-19 12:05:22
【问题描述】:

我最近开始在一个 React 项目中使用 Redux-Saga,因为它对我来说是新的,我想了解它是如何工作的。我也开始使用 Formik,因为它在 React 应用程序中管理表单的流行程度似乎超过了 Redux-Form。现在,我理解了 Dan Abramov 的基本原理,即“将 React 用于与全局应用无关且不会以复杂方式发生变异的短暂状态。”

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

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

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

This reddit thread也有这个话题,不过跟跟帖的OP差不多,不知道为什么他在Redux Promise Listener找到的解决方案没有被广泛采用?

【问题讨论】:

    标签: reactjs redux redux-saga formik


    【解决方案1】:

    我可以想象的另一种选择是在 表单提交处理程序,而不是将其委托给 saga

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

    但这让我想知道,redux-Saga 的意义何在?

    redux-saga 视为“进程管理器”,用于将异步操作设为同步。有时代码流是预期的,不会有任何意外。尽管有时并非如此,因为存在控制反转 由副作用(例如 API 调用)引起。因此,我们会在何时收到回复时产生意外和不确定性。

    我没有办法让我的表单随时了解其状态 请求而不将其存储在 Redux 状态的某个地方

    在这个Demo 中,我使用redux-sagaFormik 来控制两件事:

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

    redux 只处理uploading,而其余值由formikredux-saga 处理,这有助于提供更好的用户体验(用户有一个@ 987654335@ 指示 UI 中正在发生的事情)和 developer-experience(我们通过 yielding 响应来控制传奇中的执行流程)。

    【讨论】:

    • 感谢您的回复!我浏览了演示,并没有真正看到 Formik 在这种情况下提供的价值。您传入了一个提交处理程序,但您包装的组件似乎没有使用它。你能解释一下吗?
    • 在这种情况下解释 formik 带来的价值将超出这个问题的范围。您可以阅读有关 Formik here 的信息。关于提交处理程序,您可以阅读有关将道具传递给包装组件的信息。 请注意: 在演示中handleSubmit 使用props.uploadFile(values),然后在handleUpload 中使用。道具的流动在开始时有点难以理解,但最终它连接在一起:)
    • 将道具传递给包装组件的链接withFormik
    • 好吧,也许我的误解源于对 antd 的不熟悉,但根据我对Formik 的理解,它可以将 props 传递到包含表单的组件中。在您的演示中,我没有看到正在使用的表单元素或提交处理程序。另外,我没有看到您根据您从 redux 商店收到的道具使用 setSubmitting 之类的 formik 助手。即,我在评论中的问题不是询问 Formik 是如何工作的,而是询问您的演示中是否需要 Formik。
    【解决方案2】:

    我所做的是将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));
      }
    }
    

    【讨论】:

      猜你喜欢
      • 2023-03-24
      • 2017-09-14
      • 2017-11-28
      • 1970-01-01
      • 2019-06-14
      • 2021-06-18
      • 1970-01-01
      • 2019-07-08
      • 1970-01-01
      相关资源
      最近更新 更多