如何在 withFormik() 形式中使用 useMutation 钩子

Posted

技术标签:

【中文标题】如何在 withFormik() 形式中使用 useMutation 钩子【英文标题】:How to use useMutation hook in withFormik() form 【发布时间】:2020-08-22 02:19:57 【问题描述】:

此 Formk 表单工作正常,但是当我在表单中使用“useMutation”挂钩时,它显示错误“在上下文中找不到“客户端”或作为选项传入。将根组件包装在 中,或通过通过选项中的 ApolloClient 实例”。我也使用了“突变”,它给出了同样的错误。我认为错误在突变部分。

form.js

import React,useState from "react"
import render from "react-dom"
import withFormik, Form, Field from 'formik'
import * as Yup from "yup"
import  useMutation  from '@apollo/react-hooks';
import gql from 'graphql-tag'

const REGISTER_MUTATION=gql`
mutation ($email: String!, $password: String!, $username: String!)
createUser(
  email: $email, username: $username, password: $password)
  userusername, email
`;

const App = (values, errors, touched, isSubmitting )=> 

// Here is the problem, if i remove this portion it works fine
    const [username, setUsername]= useState("username");
    const [email, setEmail]= useState("email");
    const [password, setPassword]= useState("password");

    const [createUser] = useMutation(REGISTER_MUTATION)
        async function createNewUser() 
         await createUser( variables:  username , email , password ,
            )
        ; console.log(createUser);
//Afterwards it works fine
return(

  <Form>
    <div>
       touched.email && errors.email && <p>Invalid Email </p>
    <Field type="email" name="email" placeholder="Email" />
    </div>
    <div>
    touched.password && errors.password && <p>Invalid password </p>
    <Field type="password" name="password" placeholder="Password" />
    </div>
    <label>
    <Field type="checkbox" name="newsletter" checked=values.newsletter/>
    Ok got it
    </label>

    <Field component="select" name="plan">
      <option value="value">Free</option>
      <option value= "premium" > Premium</option>
    </Field>
    <button type="button" disabled=isSubmitting>Submit</button>
  </Form>
);

const FormikApp = withFormik(
  mapPropsToValues (email, password, newsletter, plan)
    return
      password: password || " ",
      email: email || " ",
      newsletter: newsletter || true,
      plan : plan || 'Premium'
    
  ,
validationSchema: Yup.object().shape(

    email: Yup.string().email("Invalid email account").required("field missing"),
    password: Yup.string().email().min(8,"password is weak").required()
  ),

  handleSubmit(values, setSubmitting)
    setTimeout(()=>
    setSubmitting(false)
  ,2000)
  
)(App)

render(<FormikApp  />,  document.getElementById("root"))
export default FormikApp

index.js

import React from 'react';
import ReactDOM from 'react-dom';
import * as serviceWorker from './serviceWorker';
import  FormikApp from'./component/form1';
import ApolloClient from 'apollo-boost';
import  ApolloProvider  from 'react-apollo';
import  ApolloProvider as ApolloProviderHooks  from '@apollo/react-hooks';

const client = new ApolloClient( uri: 'http://127.0.0.1:8000/graphql/' );
const App = () => (

   <ApolloProvider client=client>
<ApolloProviderHooks client=client>
    <FormikApp />
</ApolloProviderHooks>
   </ApolloProvider>
);

const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);

serviceWorker.unregister();

pakage.json


  "name": "start_react",
  "version": "0.1.0",
  "private": true,
  "dependencies": 
    "@apollo/react-hooks": "^3.1.5",
    "@emotion/core": "^10.0.28",
    "@emotion/styled": "^10.0.27",
    "@material-ui/icons": "^4.9.1",
    "@testing-library/jest-dom": "^4.2.4",
    "@testing-library/react": "^9.5.0",
    "@testing-library/user-event": "^7.2.1",
    "apollo-boost": "^0.4.7",
    "cors": "^2.8.5",
    "express": "^4.17.1",
    "formik": "^2.1.4",
    "graphql": "^15.0.0",
    "graphql-tag": "^2.10.3",
    "react": "^16.13.1",
    "react-apollo": "^3.1.5",
    "react-apollo-hooks": "^0.5.0",
    "react-dom": "^16.13.1",
    "react-scripts": "3.4.1"
  ,
  "scripts": 
    "start": "react-scripts start",
    "build": "react-scripts build",
    "test": "react-scripts test",
    "eject": "react-scripts eject"
  ,
  "eslintConfig": 
    "extends": "react-app"
  ,
  "browserslist": 
    "production": [
      ">0.2%",
      "not dead",
      "not op_mini all"
    ],
    "development": [
      "last 1 chrome version",
      "last 1 firefox version",
      "last 1 safari version"
    ]
  

【问题讨论】:

handleSubmit中调用createUser(在变量中传递值) 我试过这个handleSubmit(values, setSubmitting, createUser) setTimeout(()=&gt; setSubmitting(false) ,2000) createUser( variables: ...values, email : $values.email ,密码:$values.password ,用户名:$values.username` ); console.log(values)` 并得到错误 TypeError: createUser is not a function at Object.handleSubmit createUser 已在组件 [global] 范围内定义,您无需将其定义为 handleSubmit 参数 现在错误“第 149:6 行:'createUser' 未定义 no-undef” hmmm...withFormik,因为 HOC 在外面...将其转换为useFormik,在useMutation 之后声明? ...或将 放置在带有“useMutation”的某些功能组件中 ...将突变移到外部 .... const MutationWithFormik = () =&gt; const [createUser] = useMutation(REGISTER_MUTATION); return &lt;FormikApp createUser /&gt;; ...在handleSubmit中使用props.createUser ...当然渲染MutationWithFormik作为主要 【参考方案1】:

在你的form.js 中不要这样做render(&lt;FormikApp /&gt;, document.getElementById("root"))

您正在渲染&lt;FormikApp /&gt;,如您所见,您需要使用ApolloProvider 包装&lt;FormikApp /&gt;,因为useMutation 需要apollo 客户端。

如果您删除render(&lt;FormikApp /&gt;, document.getElementById("root")),我相信您的问题不会持续存在

编辑

工作示例:https://codesandbox.io/s/awesome-ishizaka-kuhxi

您可以为您的FormikApp 制作一个包装器。像这样的:

import React from "react";
import  withFormik, Form, Field  from "formik";
import * as Yup from "yup";
import  useMutation  from "@apollo/react-hooks";
import gql from "graphql-tag";

const REGISTER_MUTATION = gql`
  mutation($email: String!, $password: String!, $username: String!) 
    createUser(email: $email, username: $username, password: $password) 
      user 
        username
        email
      
    
  
`;

const App = ( values, errors, touched, isSubmitting ) => 
  //Afterwards it works fine
  return (
    <Form>
      <div>
        touched.email && errors.email && <p>Invalid Email </p>
        <Field type="email" name="email" placeholder="Email" />
      </div>
      <div>
        touched.password && errors.password && <p>Invalid password </p>
        <Field type="password" name="password" placeholder="Password" />
      </div>
      <label>
        <Field type="checkbox" name="newsletter" checked=values.newsletter />
        Ok got it
      </label>

      <Field component="select" name="plan">
        <option value="value">Free</option>
        <option value="premium"> Premium</option>
      </Field>
      <button type="submit" disabled=isSubmitting>
        Submit
      </button>
    </Form>
  );
;

const FormikApp = withFormik(
  mapPropsToValues( email, password, newsletter, plan ) 
    return 
      password: password || " ",
      email: email || " ",
      newsletter: newsletter || true,
      plan: plan || "Premium"
    ;
  ,
  validationSchema: Yup.object().shape(
    email: Yup.string()
      .email("Invalid email account")
      .required("field missing"),
    password: Yup.string()
      .email()
      .min(8, "password is weak")
      .required()
  ),

  handleSubmit(values,  props ) 
    props.createUser(
      variables: values
    );
  
)(App);

const FormikWrapper = () => 
  const [createUser] = useMutation(REGISTER_MUTATION);
  return <FormikApp createUser=createUser />;
;

export default FormikWrapper;

【讨论】:

useMutation 仍然不能与Formik一起工作,任何建议 您能详细说明一下吗?什么不工作?什么错误? 我想用这个 useMutation 代码 sn-p 来改变值,但它根本不起作用,你能写下我将如何在这个表单上下文中改变值吗?谢谢 @saud00 如果我正确理解您的问题,您是在问如何在withFormikhandleSubmit 中调用突变? 是的,如何调用withFormikhandleSubmit中的突变?使用 useMutation 钩子。

以上是关于如何在 withFormik() 形式中使用 useMutation 钩子的主要内容,如果未能解决你的问题,请参考以下文章

如何使用python计算一列中每行的唯一值?

如何下载(或以 blob 形式获取)用于流式传输 HTML5 视频的 MediaSource?

(123456789).toLocaleString('en-US')

如何避免 .s3-website-us-east-1.amazonaws.com/ 在 URL 中?

linux中如何将us-ascii转换成utf-8格式

java中的Date怎么转换成YYYYMMDD形式?