如何从 From 外部更改 Formik TextField 值?

Posted

技术标签:

【中文标题】如何从 From 外部更改 Formik TextField 值?【英文标题】:How do I change a Formik TextField value from the outside of the From? 【发布时间】:2020-08-01 13:45:22 【问题描述】:

在模块对话框中,我想更改输入值 (#quaggaIsbn) 的值。我试过document.getElementById("quaggaIsbn").value = result.codeResult.code,但它没有反映到表单发送到服务器的值上。如何更改 Formik 发送到服务器的值?

NewProjectDialog.js

import React from 'react';
import PropTypes from 'prop-types'
import  Formik, Field, Form  from 'formik'
import  TextField from 'formik-material-ui'
import  makeStyles  from '@material-ui/core/styles'
import Button from '@material-ui/core/Button'
import Dialog from '@material-ui/core/Dialog'
import DialogTitle from '@material-ui/core/DialogTitle'
import DialogActions from '@material-ui/core/DialogActions'
import DialogContent from '@material-ui/core/DialogContent'
import styles from './NewProjectDialog.styles'
import Quagga from 'quagga';

const useStyles = makeStyles(styles)

function NewProjectDialog( onSubmit, open, onRequestClose ) 
  const classes = useStyles()

  function handleSubmit(values,  setSubmitting ) 
    return onSubmit(values).then(() => 
      setSubmitting(false)
    )
  



  function inputFile()
    const file = document.getElementById("quaggaFile").files[0];
    const reader = new FileReader();
    reader.addEventListener("load", function () 
      // convert image file to base64 string
      analyzeQuaggaFile(reader.result);
      //preview.src = reader.result;
    , false);
    reader.readAsDataURL(file);
  

  function analyzeQuaggaFile(src)
  Quagga.decodeSingle(
//    src: "/image-002.jpg",
    src: src,
    numOfWorkers: 0,  // Needs to be 0 when used within node
    inputStream: 
        size: 800  // restrict input-size to be 800px in width (long-side)
    ,
    decoder: 
        readers: ["ean_reader"] // List of active readers
    ,
  , function(result) 
      if(result.codeResult) 
          console.log("result", result.codeResult.code);
          document.getElementById("quaggaIsbn").value = result.codeResult.code  ;
       else 
          console.log("not detected");
      
  );


  return (
    <Dialog open=open onClose=onRequestClose>
      <DialogTitle id="new-project-dialog-title">Sell book</DialogTitle>

      <Formik initialValues= name: ''  onSubmit=handleSubmit>
        ( errors, isSubmitting ) => (
          <Form className=classes.root>
            <DialogContent>
              <Field
                id="quaggaIsbn"
                name="isbn"
                label="ISBN"
                component=TextField
                margin="normal"
                fullWidth
              />
              Scan bar code:<input id="quaggaFile" type="file" accept="image/*" capture="camera" onChange=inputFile/>
              <Field
                name="title"
                label="Title"
                component=TextField
                margin="normal"
                fullWidth
              />
              <Field
                name="status"
                label="Status"
                component=TextField
                margin="normal"
                fullWidth
              />
              <Field
                name="price"
                label="Price"
                component=TextField
                margin="normal"
                fullWidth
              />
              Book cover:<input id="image" type="file"/>
            </DialogContent>
            <DialogActions>
              <Button onClick=onRequestClose color="secondary">
                Cancel
              </Button>
              <Button type="submit" color="primary" disabled=isSubmitting>
                isSubmitting ? 'Creating...' : 'Create'
              </Button>
            </DialogActions>
          </Form>
        )
      </Formik>


    </Dialog>
  )


NewProjectDialog.propTypes = 
  onSubmit: PropTypes.func.isRequired,
  open: PropTypes.bool.isRequired,
  onRequestClose: PropTypes.func.isRequired


export default NewProjectDialog

【问题讨论】:

您想设置默认值还是应该何时更改该值? 当我选择一个文件并加载到#quaggaFile 时,我想更改#quaggaIsbn 的值。 (它反映到视图而不是表单信息,当我提交表单时,它不会发送到服务器。) 当我上传文件时,会调用 inputFile()。调用analyzeQuaggaFile() 和analyzeQuaggaFile() 尝试更改表单值#quaggaIsbn,但似乎没有因为#quaggaIsbn 的值未包含在提交的数据中。 【参考方案1】:

一旦使用 enableReinitialize 属性在其上下文之外更新其属性,就可以重置整个 Formik。

https://formik.org/docs/api/formik#enablereinitialize-boolean

像这样:

<Formik validationSchema=validationSchema initialValues=this.state.formValues onSubmit=this.handleFormSubmission enableReinitialize=true>

【讨论】:

【参考方案2】:

Formik 渲染方法提供了一个使用 setFieldValue 手动更改字段值的道具,它将字段名称和新值作为参数,您可以从 here 了解更多信息

至于你需要改变的是这里

// accept a new parameter which you can pass to the `analyzeQuaggaFile` function
function inputFile(setFieldValue) 
  const file = document.getElementById("quaggaFile").files[0];

  const reader = new FileReader();

  reader.addEventListener(
    "load",
    function () 
      // pass the setFieldValue
      analyzeQuaggaFile(reader.result, setFieldValue);
    ,
    false
  );

  reader.readAsDataURL(file);


// second parameter is setFieldValue
function analyzeQuaggaFile(src, setFieldValue) 
  Quagga.decodeSingle(
    
      src: src,
      numOfWorkers: 0,
      inputStream: 
        size: 800,
      ,
      decoder: 
        readers: ["ean_reader"],
      ,
    ,
    function (result) 
      if (result.codeResult) 
        // update the isbn field value
        setFieldValue("isbn", result.codeResult.code);
       else 
        console.log("not detected");
      
    
  );

现在在你的 JSX 代码中改变这个:

<Formik initialValues= name: ""  onSubmit=handleSubmit>
  ( errors, isSubmitting, setFieldValue ) => (
    <Form className=classes.root>
      /* Other fields */
      Scan bar code:
      <input
        id="quaggaFile"
        type="file"
        accept="image/*"
        capture="camera"
        onChange=() => inputFile(setFieldValue) // pass the setFieldValue property from formik 
      />
      /* Other fields */
    </Form>
  )
</Formik>;

【讨论】:

太棒了!谢谢!!【参考方案3】:

    import 
      useFormik
     from "formik";
    import * as yup from 'yup';

    export default function ChangeFormikValueOutsideForm() 
      const initialValues = 
        first_name: 'John',
        last_name: 'Doe'
      
      const validationSchema = yup.object(
        first_name: yup.string("must be a string")
          .required("Must have a first name"),
        last_name: yup.string("must be a string")
      )
      const formik = useFormik(
          initialValues,
          validationSchema,
          onSubmit: (values) => 
        )
      
    

    let handleLastNameChange = () => 
      formik.setFieldValue('last_name', Math.ceil(Math.random() * 100))
    

    return (
    <form onSubmit = 
        formik.handleSubmit
       >
      <p> First Name * </p> 
      <input
        name = "first_name"
        id = "first_name"
        type = "text"
        onChange = 
          formik.handleChange
        
        value = 
          formik.values.first_name
        
      />
      <p> Last Name </p>
      <input
        name = "last_name"
        id = "last_name"
        type = "text"
        onChange = 
          handleLastNameChange
        
        value = 
          formik.values.last_name
        
      />
      <input
        type = "submit"
        value = "Submit Form"
      />
      </form>
      )
    

它与 useFormik 钩子一起工作,这允许您在 formik 标记之外定义表单,然后从 formik 变量中受益,以在表单之外执行 setFieldValue 方法。事实上,您正在处理的表格完全脱离了表格;)

与材质 ui 一起使用的想法也相同。它有效

【讨论】:

以上是关于如何从 From 外部更改 Formik TextField 值?的主要内容,如果未能解决你的问题,请参考以下文章

如何从钩子内的 Formik 中获取值?

当我提交表单并尝试更改值时,Formik + Material UI 错误

React Formik Material UI Autocomplete:如何从 localStorage 填充自动完成内部的值?

如何使用 Formik 在 react-datepicker 中设置初始日期?

[React] Validate React Forms with Formik and Yup

如何通过打字稿在Formik中添加强类型字段?