React ref 和 Formik innerRef - current.values 未更新

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

我正在尝试将 Formik 与 React 的

useRef
钩子结合使用来创建对我的表单的引用,然后我可以在该表单之外访问该引用。但是,无论我做什么,引用中的值都不会像我期望的那样更新。

我创建了一个小示例来演示该问题。

import React, { useEffect, useRef, useMemo } from "react";
import { render } from "react-dom";
import { Formik } from "formik";

const App = () => {
  const formRef = useRef();

  useEffect(() => {
    console.log("formRef changed", formRef.current);
  }, [formRef]);

  const email = useMemo(() => {
    if (formRef.current) {
      const email = formRef.current.values;
      return email;
    }

    return "<none>";
  }, [formRef.current?.values]); //This dependency array was a test, I tried formRef and formRef.current separately aswell.

  return (
    <div className="app">
      <Formik
        innerRef={(f) => (formRef.current = f)}
        initialValues={{ email: "[email protected]" }}
        onSubmit={(values) => {
          console.log(values);
        }}
      >
        {(props) => {
          const {
            values,
            isSubmitting,
            handleChange,
            handleReset,
            handleSubmit
          } = props;
          return (
            <form onSubmit={handleSubmit}>
              <label htmlFor="email" style={{ display: "block" }}>
                Email
              </label>
              <input
                id="email"
                placeholder="Enter your email"
                type="text"
                value={values.email}
                onChange={handleChange}
              />
              <button type="button" className="outline" onClick={handleReset}>
                Reset
              </button>
              <button type="submit" disabled={isSubmitting}>
                Submit
              </button>
            </form>
          );
        }}
      </Formik>
      <span>Entered e-mail: {email}</span>
    </div>
  );
};

render(<App />, document.getElementById("root"));


不幸的是,我无法让它与 Stack Snippets 一起使用,所以我制作了一个codesandbox: https://codesandbox.io/s/formik-example-forked-0osy6?file=/index.js

我最初想这样做,因为我需要这个值在与表单完全无关的地方。我考虑过只使用状态变量,但这感觉像是不必要地重复状态,但我可能是错的。

非常感谢!

reactjs formik react-ref
4个回答
0
投票

useRef 无法通知,无法重新渲染 React 组件。 要重新渲染页面,您需要在值更新时使用 useState 来更新组件。


0
投票

而不是使用

const formRef = useRef();

使用:
const [values, setValues] = useState({});

在 Formik 中替换

innerRef={(f) => (formRef.current = f)}
与:
innerRef={(formikActions) => (formikActions? setValues(formikActions.values) : setValues({})}

现在你可以更新 useEffect 来监听值状态,因此更改将始终被监听。

useEffect(() => {
    console.log("values changed", values);
  }, [values]);

0
投票

反应

useRef
无法随着状态变化而更新。如果您需要这些值,则无法更新,您必须尝试其他方法,或者使用 Formik
useField
来获取您要使用的字段的值。


0
投票

您完全可以通过使用 Ref. 从其他地方访问 Formik 的值。在这里,当我为提交按钮添加回调时,您可以看到值已更新。

// Helper styles for demo
import "./helper.css";

import React, { useEffect, useRef, useState } from "react";
import { render } from "react-dom";
import { Formik } from "formik";

const App = () => {
  const formRef = useRef();
  const [email, setEmail] = useState("");

  useEffect(() => {
    console.log("formRef changed", formRef.current);
  }, [formRef]);

  const submitForm = () => {
    setEmail(formRef.current.values.email);
  };

  const resetForm = () => {
    formRef.current.resetForm();
  };

  // const email = useMemo(() => {
  //   if (formRef.current) {
  //     const email = formRef.current.values;
  //     return email;
  //   }

  //   return "<none>";
  // }, [formRef.current?.values]);

  return (
    <div className="app">
      <Formik
        enableReinitialize
        innerRef={(f) => (formRef.current = f)}
        initialValues={{ email: "[email protected]" }}
        onSubmit={(values) => {
          console.log(values);
        }}
      >
        {(props) => {
          const {
            values,
            isSubmitting,
            handleChange,
            handleReset,
            handleSubmit
          } = props;
          return (
            <form onSubmit={handleSubmit}>
              <label htmlFor="email" style={{ display: "block" }}>
                Email
              </label>
              <input
                id="email"
                placeholder="Enter your email"
                type="text"
                value={values.email}
                onChange={handleChange}
              />
              <button type="button" className="outline" onClick={resetForm}>
                Reset
              </button>
              <button disabled={isSubmitting} onClick={submitForm}>
                Submit
              </button>
            </form>
          );
        }}
      </Formik>
      <span>Entered e-mail: {email}</span>
    </div>
  );
};

render(<App />, document.getElementById("root"));

沙盒中的工作代码在这里 https://codesandbox.io/s/formik-example-forked-7nxcni?file=/index.js

此外,您还可以将 ref 放在父组件中并将其传递给子组件。检查这个沙箱,https://codesandbox.io/s/formik-example-forked-pfri64?file=/index.js

© www.soinside.com 2019 - 2024. All rights reserved.