简体   繁体   中英

React hook useState not updating with onSubmit

I'm currently experiencing an issue pushing the input field value to state onSubmit.

codesandbox

I'm trying to set an input field value to the state so that I can use that value once the component is updated to redirect the user to another page. I tested the path manually and it works, but since the state is not updating synchronously, the redirect does not work. I can render the input value on the page, but if I try to log it, it long undefined(for the first time) and the previous state on a second submit.

import React, { useRef, useState } from "react";
import { db } from "../firebase";
import { Redirect } from "@reach/router";

function CreateProject(props) {
  const [id, setID] = useState(null);
  const colorRef = useRef(null);
  const projectNameRef = useRef(null);

  const handleSubmit = e => {
    e.preventDefault();
    const project = {
      name: projectNameRef.current.value,
      colors: [colorRef.current.value],
      colorName: colorNameRef.current.value,
      createdAt: new Date()
    };
    setID(projectNameRef.current.value);

    db.collection("users")
      .doc(`${props.user}`)
      .collection("projects")
      .doc(`${projectNameRef.current.value}`)
      .set({ ...project });
    e.target.reset();
  };


  return id ? (
    <Redirect from="/projects/new" to={`projects/:${id}`} noThrow />
  ) : (
    <div>
      <div>
        <h1>Create new selection</h1>
        <form onSubmit={handleSubmit}>
          <label>Color</label>
          <input ref={colorNameRef} type="text" name="colorName" />
          <label>Project Name</label>
          <input ref={projectNameRef} type="text" name="projectName" required />
          <button type="submit">Submit</button>
        </form>
      </div>
    </div>
  );
}

export default CreateProject;

react: 16.8.6

That's the way react hooks useState works, to do something after a state change you should perform it inside a useEffect hook, like the following:

useEffect(() => {
  if (id) {
    console.log(id);
    projectNameRef.current.value = ''
  }
}, [id])

This effect will run every time the id value changes (and in the first render) so you could add your logic there and perform your desired actions based on the state change.

I think your use of ref here is inappropriate and may be causing the issue. I would rewrite your function like this.

function CreateProject() {
  const [id, setID] = useState(null);
  const [shouldRedirect, setShouldRedirect] = useState(false);

  const handleSubmit = e => {
    e.preventDefault();
    setShouldRedirect(true);
  };

  const handleChange = (e) => {
    setID(e.target.value);
  }

  return shouldRedirect ? (
    <Redirect from="/projects/new" to={`projects/:${id}`} noThrow />
  ) : (
    <div>
      <div>
        <h1>Create new selection</h1>
        <form onSubmit={handleSubmit}>
          <label>Project Name</label>
          <input onChange={handleChange} type="text" name="projectName" required />
          <button type="submit">Submit</button>
        </form>
      </div>
    </div>
  );

In this way your state is always being updated and therefore so is your redirect URL. When you submit, you simply tell the component it should now submit with the current ID.

You can see how this works from the React documentation.

You may even be able to replace the conditional render with a functional call to history.push using withRouter . See advice on this question.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM