首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >防止在更改路线时提交Formik AutoSave

防止在更改路线时提交Formik AutoSave
EN

Stack Overflow用户
提问于 2019-12-11 11:41:03
回答 2查看 1.6K关注 0票数 5

我的应用程序有组件的表单。更改表单值后,此组件调用提交。一切运行良好,但当更改路由时,它会更改表单值和<AutoSave/>调用提交。如何解决这个问题?一个可能的解决方案是在更改路由时再次挂载<AutoSave/>

码箱

AutoSave:

代码语言:javascript
复制
import React, { useEffect, useCallback } from 'react'
import { useFormikContext } from 'formik'
import debounce from 'lodash.debounce'

const AutoSave = ({ debounceMs }) => {
  const formik = useFormikContext()

  const debouncedSubmit = useCallback(
    debounce(formik.submitForm, debounceMs),
    [formik.submitForm, debounceMs]
  )

  useEffect(() => debouncedSubmit, [debouncedSubmit, formik.values])

  return <>{!!formik.isSubmitting && "saving..."}</>
}

我的应用程序:

代码语言:javascript
复制
const App: FC = () => {
  const {books} = getBooks() // [{id: 1, title: 'test', summary: 'test'}, ...]
  const {query} = useRouter()

  const handleSubmit = useCallback(async values => {
    try {
      await API.patch('/books', {id: query.book, ...values})
    } catch (e) {}
  }, [query.book])

  return (
    <>
      <span>Books</span>
      {books.map(({id, title}, key) => (
        <Link key={key} href='/book/[book]' as={`/book/${id}`}>
          <a>{title}</a>
        </Link>
      ))}
      {query.book && (
        <MainForm  
         book={books.find(book => book.id === query.book)}
         handleSubmit={handleSubmit}/>
      )}
    </>
  )
}

MainForm:

代码语言:javascript
复制
type Props = {
  book: BookProps // {id: string, title: string ...},
  handleSubmit: (values) => Promise<void>
}

const MainForm: FC<Props> = ({book, handleSubmit}) => (
  <Formik 
    enableReinitialize 
    initialValues={{title: book.title, summary: book.summary}}
    handleSubmit={values => handleSubmit(values)}>
    {() => (
      <Form>
        //...My fields...
        <AutoSave debounceMs={500}/> // <=== AutoSave with debounce
      </Form>
    )}
  </Formik>
)
EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2019-12-11 18:15:11

查看一下:https://codesandbox.io/s/clever-sun-057vy

代码语言:javascript
复制
# Problem

useEffect(() => debouncedSubmit, [debouncedSubmit, formik.values]);

即使在组件挂载时,formik.values也始终会更改。这就是为什么debouncedSubmit在路由更改时被调用的原因。

因此,基本上,我们不希望首先将其作为组件来运行,而是当用户更改表单时。

formik.dirty是关键。只需在提交之前检查一下formik.dirty即可。

代码语言:javascript
复制
const AutoSave = ({ debounceMs }) => {
  const formik = useFormikContext();

  const debouncedSubmit = useCallback(
    debounce(formik.submitForm, debounceMs),
    [formik.submitForm, debounceMs]
  );

  useEffect(() => {
    formik.dirty && debouncedSubmit();
  }, [debouncedSubmit, formik.dirty, formik.values]);

  return <>{!!formik.isSubmitting && 'saving...'}</>;
};

另一件事是Formik实例。这个Formik将用于所有的书籍。因此,在将新书装订到其中时,您需要使用enableReinitialize 道具重新设置表单。

代码语言:javascript
复制
<Formik
  enableReinitialize
  initialValues={{ title: book.title, summary: book.summary, id: book.id }}
  onSubmit={values => handleSubmit(values)}
>

或使用key={book.id}对每本书使用单独的实例

代码语言:javascript
复制
<Formik
  key={book.id}
  initialValues={{ title: book.title, summary: book.summary, id: book.id }}
  onSubmit={values => handleSubmit(values)}
>
票数 5
EN

Stack Overflow用户

发布于 2019-12-11 15:17:26

您需要有类似于firstSubmit的东西,在这里您可以检查firstSubmit是否已经发生,所以它只在第二个提交时调用AutoSave (在那里它实际上已经改变了)。

代码语言:javascript
复制
const AutoSave = ({debounceMs}) => {
    const [firstSubmit, setFirstSubmit] = React.useState(false)
    const formik = useFormikContext();

    const debouncedSubmit = React.useCallback(
      debounce(firstSubmit ? formik.submitForm : () => setFirstSubmit(true), debounceMs),
      [debounceMs, formik.submitForm, firstSubmit, setFirstSubmit]
    );

    React.useEffect(debouncedSubmit , [debouncedSubmit, formik.values]);

    return <>{!!formik.isSubmitting ? 'saving...' : null}</>;
}

我不确定这些代码是否有效,我还没有测试它,因为我不确定debounce是从哪里来的,但逻辑是这样的。

您应该检查它是否已经提交了一次,如果是的话,跳过它,只在第二次提交的时候进行。

如果您提供了一个有用的示例,我可以测试它,如果上面的代码不能工作,我可以让它工作。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/59285019

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档