Formik setFieldValue 在函数内

问题描述 投票:0回答:5

如果我有一个功能组件并且想要在 Formik 标签之外设置一个值,我该怎么做?下面是我需要进一步说明的代码。

function XYZScreen() {

    const someFunctionWithLogic = () => {
        // Set the value of the number field here...
    }
    
    return (
        <Screen>
            <Formik>
                <FormField name="number" placeholder="Number" />
             </Formik>
        </Screen>            
    );
}

我已将代码减少到尽可能少,以简化问题。这个问题在问题的上下文中可能没有意义,但我认为我的要求很清楚。

如果您需要更多代码,请告诉我,如果需要,我很乐意提供。

reactjs react-native formik
5个回答
22
投票

您可以使用

useFormik
钩子代替:

import { useFormik } from 'Formik'

function XYZScreen() {

    const formikProps = useFormik({
        initialValues,
        validationSchema,
        onSubmit: yourSubmitFunction,
        ...etc
    })

    const someFunctionWithLogic = () => {
        // Set the value of the number field here:
        formikProps.setFieldValue("number", someNumber)
    }
    
    return (
        <Screen>
            {/* No need for Formik component */}
            <FormField 
                name="number" 
                placeholder="Number" 
                value={formikProps.values.number} // or whatever the value is
                onChange={formikProps.handleChange}
            />
        </Screen>            
    );
}

因此,您基本上是在函数体内设置所有表单道具,并且可以在那里访问它们。 Formik 有很多很棒的辅助钩子和函数,我强烈建议梳理文档。

编辑:另一种方式

如果您真的喜欢

Formik
标签,您可以继续使用它。只需创建一个
Formik
包装器组件,并使用
useFormikContext
:

在后代中使用自定义逻辑
// FormWrapper.js

const FormWrapper = () => (
  <Formik
    initialValues={initialValues}
    validationSchema={validationSchema}
    onSubmit={yourOnSubmitFunction}
  >
    <SomeChild />
  </Formik>
)

// SomeChild.js

const SomeChild = () => {

  // returns all values and methods from your Formik tag
  const formikProps = useFormikContext()

  const someFunctionWithLogic = () => {
    formikProps.setFieldValue("number", someNumber)
  }
    
  return (
    <Screen>
      <FormField 
        name="number" 
        placeholder="Number" 
        value={formikProps.values.number} // or whatever the value is
        onChange={formikProps.handleChange}
      />
    </Screen>            
    );
}

2
投票

实现此目的的最佳方法是将 setFieldValue 函数传递给您想要的函数,因此代码应如下所示

function XYZScreen() {

const someFunctionWithLogic = (value, setFieldValue) => {
    // Set the value of the number field here...
    setFieldValue('price', value)
}

return (
    <Screen>
        <Formik>
            <FormField name="number" placeholder="Number" onChange={(e) => { handleChange(e); someFunctionWithLogic(value, setFieldValue ); }} />
         </Formik>
    </Screen>            
);
}

参考https://web-brackets.com/discussion/12/how-to-use-setfieldvalue-from-outside-render-function-formik


2
投票

我自己也遇到了类似的问题,并根据 Seth Lutske 的评论提出了另一个解决方案。您可以将使用

useFormik
与手动创建 Formik 上下文结合起来。
useFormik
非常强大,但它的缺点是它不会创建上下文,因此你不能在子组件中使用
useField
useFormikContext
,并且需要手动传递所有相关的props(value,onChange,onBlur)等)。

您可以做的是使用

useFormik
创建 Formik 上下文对象,并使用
<FormikProvider>
手动向下传递上下文。通过这种方法,您可以继续使用所有字段,就像它们被包裹在
<Formik>

中一样

import { useFormik, FormikProvider } from 'formik'

function XYZScreen() {
    const formikProps = useFormik({
        initialValues,
        validationSchema,
        onSubmit: yourSubmitFunction,
        ...etc
    })

    const someFunctionWithLogic = () => {
        // Set the value of the number field here:
        formikProps.setFieldValue("number", someNumber)
    }
    
    return (
        <Screen>
          {/* FormikProvider component instead of Formik */}
          <FormikProvider value={formikProps}>  
            <FormField 
              name="number" 
              placeholder="Number" 
            />
          </FormikProvider>  
        </Screen>            
    );
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>


0
投票

您也可以使用

initialValues

轻松完成此操作
 <Formik
    initialValues={{
      "fieldName": this.state.value,
    }}
    enableReinitialize
    ...
 >
 ...
</Formik>

同样对于功能组件,您可以使用

useEffect
内的
Formik
来完成此操作,使用
const [value,setValue] = useState()

设置值
<Formik
  initialValues={{}}
  onSubmit={(values, { resetForm }) => _submit(values, resetForm)}
  validationSchema={buildValidationSchema(actionItem.fields)}
>
{({ setFieldValue, handleSubmit, values, errors, touched }) => {
    useEffect(() => {
       setFieldValue("fieldName",value); 
    }, [value]); 
...
</Formik>

-1
投票

为什么不尝试使用

initialProps
重置表单?

function XYZScreen() {

    const [number, setNumber] = useState()

    const someFunctionWithLogic = () => {
        // Set the value of the number field here...
        setNumber(...)
    }
    
    return (
        <Screen>
            <Formik initialProps={{number}}>
                <FormField name="number" placeholder="Number" />
             </Formik>
        </Screen>            
    );
}

另一个建议是将该数字传递给 Formik 的内部组件:


function SomeChild(props) {
    const {number, setFieldValue} = props;
    
    useEffect(() => {
       setFieldValue('number', number);
    }, [number]);

    return (
       <FormField name="number" placeholder="Number" />
    )
}

function XYZScreen() {

    const [number, setNumber] = useState()

    const someFunctionWithLogic = () => {
        // Set the value of the number field here...
        setNumber(...)
    }
    
    return (
        <Screen>
            <Formik>
                {(props) => <SomeChild number={number} {...props} />
             </Formik>
        </Screen>            
    );
}
© www.soinside.com 2019 - 2024. All rights reserved.