programing

React Formik 외부에서 submit Form 사용

copyandpastes 2023. 3. 27. 22:29
반응형

React Formik 외부에서 submit Form 사용

현재의 동작

<Formik
    isInitialValid
    initialValues={{ first_name: 'Test', email: 'test@mail.com' }}
    validate={validate}
    ref={node => (this.form = node)}
    onSubmitCallback={this.onSubmitCallback}
    render={formProps => {
        const fieldProps = { formProps, margin: 'normal', fullWidth: true, };
        const {values} = formProps;
        return (
            <Fragment>
                <form noValidate>
                    <TextField
                        {...fieldProps}
                        required
                        autoFocus
                        value={values.first_name}
                        type="text"
                        name="first_name"

                    />

                    <TextField
                        {...fieldProps}
                        name="last_name"
                        type="text"
                    />

                    <TextField
                        {...fieldProps}
                        required
                        name="email"
                        type="email"
                        value={values.email}

                    />
                </form>
                <Button onClick={this.onClick}>Login</Button>
            </Fragment>
        );
    }}
/>

https://github.com/jaredpalmer/formik/issues/73#issuecomment-317169770에서 이 솔루션을 시도하고 있지만 항상 반환됩니다.Uncaught TypeError: _this.props.onSubmit is not a function

가 때console.log(this.form)submitForm★★★★★★ 。

해결방법은 없나요?


- Formik 버전 : 최신 - 리액트 버전 : v16 - OS : Mac OS

리액트 훅을 통한 솔루션이 무엇인지 궁금해 하는 분들을 위해:

Formik 2.x, 이 답변에서 설명한 바와 같이

// import this in the related component
import { useFormikContext } from 'formik';

// Then inside the component body
const { submitForm } = useFormikContext();

const handleSubmit = () => {
  submitForm();
}

이 솔루션은 컨텍스트 API를 사용하기 때문에 Formik 구성 요소 내의 구성 요소에만 작동합니다.어떤 이유로 외부 컴포넌트 또는 Formik이 실제로 사용되는 컴포넌트에서 수동으로 제출하고 싶은 경우에도 실제로 사용할 수 있습니다.innerRef

가 TLDR의 합니다.<Formik> ★★★★★★★★★★★★★★★★★」withFormik()컴포넌트 의 경우는, 「」, 「」를 합니다.innerRef이하에 답해 주세요.

폼익 1.5.x+

// Attach this to your <Formik>
const formRef = useRef()

const handleSubmit = () => {
  if (formRef.current) {
    formRef.current.handleSubmit()
  }
}

// Render
<Formik innerRef={formRef} />

수 요.formikProps.submitForm 전송로 전송한 후 컴포넌트로부터의 (Formik의 프로그램 전송).

import React from 'react';
import { Formik } from 'formik';

class MyForm extends React.Component {
    render() {
        const { bindSubmitForm } = this.props;
        return (
            <Formik
                initialValues={{ a: '' }}
                onSubmit={(values, { setSubmitting }) => {
                    console.log({ values });
                    setSubmitting(false);
                }}
            >
                {(formikProps) => {
                    const { values, handleChange, handleBlur, handleSubmit } = formikProps;

                    // bind the submission handler remotely
                    bindSubmitForm(formikProps.submitForm);

                    return (
                        <form noValidate onSubmit={handleSubmit}>
                            <input type="text" name="a" value={values.a} onChange={handleChange} onBlur={handleBlur} />
                        </form>
                    )
                }}
            </Formik>
        )
    }
}

class MyApp extends React.Component {

    // will hold access to formikProps.submitForm, to trigger form submission outside of the form
    submitMyForm = null;

    handleSubmitMyForm = (e) => {
        if (this.submitMyForm) {
            this.submitMyForm(e);
        }
    };
    bindSubmitForm = (submitForm) => {
        this.submitMyForm = submitForm;
    };
    render() {
        return (
            <div>
                <button onClick={this.handleSubmitMyForm}>Submit from outside</button>
                <MyForm bindSubmitForm={this.bindSubmitForm} />
            </div>
        )
    }
}

export default MyApp;

제가 찾은 최고의 솔루션은 https://stackoverflow.com/a/53573760에 기재되어 있습니다.

답변을 여기에 복사:

양식에 "id" 특성 추가: id='my-form'

class CustomForm extends Component {
    render() {
        return (
             <form id='my-form' onSubmit={alert('Form submitted!')}>
                // Form Inputs go here    
             </form>
        );
    }
}

그런 다음 양식 외부에 있는 대상 단추의 "양식" 속성에 동일한 ID를 추가합니다.

<button form='my-form' type="submit">Outside Button</button>

이제 'Outside Button' 버튼은 양식 안에 있는 것처럼 완전히 동일합니다.

주의: IE11에서는 지원되지 않습니다.

같은 문제를 안고 매우 간단한 해결책을 찾았습니다.이것이 도움이 되었으면 합니다.

는 쉽게 할 수 html ★★★★★★★★★★★★를 붙이면,id를 달다form의 '버튼해서 '을할 수 .form붙이다

예:

      <button type="submit" form="form1">
        Save
      </button>
      <form onSubmit={handleSubmit} id="form1">
           ....
      </form>

양식과 버튼을 다른 위치에 배치할 수 있습니다.

이 버튼을 누르면 폼 제출 기능이 트리거되고 정상적으로 프로세스를 계속하는 폼이 캡처됩니다.(버튼이 렌더링되는 동안 폼이 화면에 렌더링되는 한 폼과 버튼이 어디에 있든 작동됩니다.)

컴포넌트로 컴포넌트로 변환됩니다.useFormikContext트리 아래 임의의 장소에서 submit을 사용할 수 있는 방법을 제공합니다.

   const { values, submitForm } = useFormikContext();

PS: 이것은 실제로 전화할 필요가 없는 사용자에게만 해당됩니다.Formik컴포넌트입니다.그래서 참조를 사용하는 대신에Formik트리의 합니다.useFormikContext, 꼭 해야 하는 하지 않으면 안 됩니다.Formik 그럼 이렇게 돼요.useRef .

<Formik innerRef={formikRef} />

https://formik.org/docs/api/useFormikContext

2021년에는 16.13.1을 사용하여 다음과 같은 몇 가지 요건을 충족했습니다.

  • Submit ] / [ Reset ]은 [Submit] / [ ]버튼 할 수 .<Formik> 하는같아useFormikContext내 것보다 간단하기 때문에 대답할 수 있습니다.(내 것으로, 송신하는 폼을 변경할 수 있습니다(앱바는 1개이지만, 유저는 복수의 폼을 참조할 수 있습니다).
  • 외부 제출/재설정 버튼은 Formik 양식을 전송하고 재설정할 수 있어야 합니다.
  • 이 더러워질 컴포넌트는 의 "/"를할 수 합니다).dirty□□□□□□□□★

은 다음과 의 서로 중첩된 두 개의 및 폼)를 링크하는 데 몇 공급자를 .저는 새로운 콘텍스트 프로바이더를 만들었습니다.이 프로바이더는 앱의 서로 다른 네스트된 브랜치(글로벌 앱바 및 다른 폼)에 있는 외부 컴포넌트를 링크하기 위한 것입니다.을 사용법온 다른 단의 형태뿐만 , 1개의 형태에 적응하는 것도 필요합니다.<Formik>이렇게 말합니다.

다음 예제에서는 TypeScript를 사용하지만 javascript만 알고 있다면 콜론 뒤에 있는 항목을 무시하면 JS에서도 마찬가지입니다.

<FormContextProvider>Formik 항목에 액세스해야 하는 서로 다른 컴포넌트를 모두 랩할 수 있을 정도로 앱의 용량이 높습니다.[ ] :

<FormContextProvider>
  <MyAppBar />
  <MyPageWithAForm />
</FormContextProvider>

Form Context Provider는 다음과 같습니다.

import React, { MutableRefObject, useRef, useState } from 'react'
import { FormikProps, FormikValues } from 'formik'

export interface ContextProps {
  formikFormRef: MutableRefObject<FormikProps<FormikValues>>
  forceUpdate: () => void
}

/**
 * Used to connect up buttons in the AppBar to a Formik form elsewhere in the app
 */
export const FormContext = React.createContext<Partial<ContextProps>>({})

// https://github.com/deeppatel234/react-context-devtool
FormContext.displayName = 'FormContext'

interface ProviderProps {}

export const FormContextProvider: React.FC<ProviderProps> = ({ children }) => {
  // Note, can't add specific TS form values to useRef here because the form will change from page to page.
  const formikFormRef = useRef<FormikProps<FormikValues>>(null)
  const [refresher, setRefresher] = useState<number>(0)

  const store: ContextProps = {
    formikFormRef,
    // workaround to allow components to observe the ref changes like formikFormRef.current.dirty
    forceUpdate: () => setRefresher(refresher + 1),
  }

  return <FormContext.Provider value={store}>{children}</FormContext.Provider>
}

「」를 하는 .<Formik>다음 행을 추가합니다.

const { formikFormRef } = useContext(FormContext)

컴포넌트에서는 이 를 「」에 합니다.<Formik>★★★★

innerRef={formikFormRef}

컴포넌트 에서 첫 은 " " " 입니다.<Formik>이것입니다(한 것은, 「이것」의 ).<FormContextRefreshConduit /> sline)를 참조해 주세요.

<Formik
  innerRef={formikFormRef}
  initialValues={initialValues}
  ...
>
  {({ submitForm, isSubmitting, initialValues, values, setErrors, errors, resetForm, dirty }) => (
    <Form>
      <FormContextRefreshConduit />
      ...

송신/리셋 버튼이 있는 컴포넌트에는 다음과 같은 것이 있습니다.「 」의 .formikFormRef

export const MyAppBar: React.FC<Props> = ({}) => {
  const { formikFormRef } = useContext(FormContext)
  
  const dirty = formikFormRef.current?.dirty

  return (
    <>
      <AppButton
        onClick={formikFormRef.current?.resetForm}
        disabled={!dirty}
      >
        Revert
      </AppButton>
      <AppButton
        onClick={formikFormRef.current?.submitForm}
        disabled={!dirty}
      >
        Save
      </AppButton>
    </>
  )
}

ref하지만 Formik 메서드의 Formik 메서드에 할 수 .dirty재산(재산) FormContextRefreshConduit forceUpdate이치노

감사합니다. 저는 다른 답변에서 영감을 얻어 제 모든 요구사항을 충족하는 방법을 찾았습니다.

Formik과 함께 사용한다면 다음과 같은 이점이 있습니다.

  const handleSubmitThroughRef = () => {
    newFormRef.current.dispatchEvent(
      new Event("submit", { cancelable: true, bubbles: true })
    );
  };

폼에 규칙적인 ref를 붙이면 됩니다.

  <form
        ref={newFormRef}
        
        onSubmit={handleSubmit}
      >

범인을 찾아내다

이상 없다onSubmitCallback포믹 소품 위에. 돼요.onSubmit

드셔보세요

const submitForm =({ values, setSubmiting }) =>{/...여기서 작업하세요}

<Formik on Submit={(값, {set Submiting }}=> submit Form({값, set Submiting})> {()=>(/...여기서 뭔가 실행)}

또 다른 간단한 방법은 useState를 사용하여 소품을 하위 폼 컴포넌트에 전달하는 것입니다.여기서 useEffect 후크를 사용하여 state를 설정할 수 있습니다.

const ParentComponent = () => {
  const [submitFunc, setSubmitFunc] = useState()
  return <ChildComponent setSubmitFunc={setSubmitFunc}>
}

const ChildComponent= ({ handleSubmit, setSubmitFunc }) => {
   useEffect(() => {
     if (handleSubmit) setSubmitFunc(() => handleSubmit)
   }, [handleSubmit, setSubmitFunc])

   return <></>
 }

React Class 컴포넌트에 단계별로 구현했습니다.

1 - 폼 오브젝트의 참조를 유지하기 위해 "ref" 변수를 선언했습니다(useRef는 함수 컴포넌트에서만 유효하므로 React.createRef() 함수를 사용하여 다음과 같이 코드화했습니다).

constructor(props) {
  super(props);
  this.visitFormRef = React.createRef();
}

2 - formik 폼에 "innerRef" 기능이 있기 때문에 위의 ref 변수를 할당했습니다.

<Formik 
    initialValues={initialValues}
    onSubmit={(values) => onSubmit(values)}
    validationSchema={validationSchema}
    enableReinitialize={true}
    innerRef={this.visitFormRef}  //<<--here
>

3- 아래 함수를 선언한 폼이 아닌 다른 곳에서 폼의 제출 이벤트를 트리거하려면:

triggerFormSubmit = () => {
    
    if (this.visitFormRef.current) 
        this.visitFormRef.current.handleSubmit();
}

4 - 마지막으로 외부 버튼에서 위의 함수를 호출했습니다.

<Button onClick={() => this.triggerFormSubmit()} />

혼동하지 않도록 주의해 주세요.formik 형식에 대응된 onSubmit(values) 함수는 아직 존재하며 값에서 를 가져옵니다.방금 외부 버튼에서 작동시킨 겁니다

다음은 ref를 사용하여 사용자가 외부 제출 버튼을 클릭했을 때 내부 숨겨진 제출 버튼을 클릭하는 시뮬레이션을 통해 얻은 방법입니다.

const hiddenInnerSubmitFormRef = useRef(null);

const handleExternalButtonClick = () => {
  hiddenInnerSubmitFormRef.current.click();
}

return (
<>
  {/* External Button */}
  <button onClick={handleExternalButtonClick}>
   External Submit
  </button>

  <Formik onSubmit={values => console.log(values)}>
   {() => (
     <Form>

      {/* Hide Button /*}
      <button type="submit" ref={hiddenInnerSubmitFormRef} className="hidden">
        Submit
      </button>
     </Form>
   )}
  </Formik>
 </>
)

언급URL : https://stackoverflow.com/questions/49525057/react-formik-use-submitform-outside-formik

반응형