Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I make a form submission save data in a useState hook variable?

I'm new to React and JavaScript; currently looking at hooks. I have these two React functional components in an application I generated using Create React App:

App.js

import React, { useState} from 'react';
import NameTaker from './components/NameTaker'

export default function App() {
  const [name, setName] = useState(null);

  if (name == null) {
    return <NameTaker onSubmit={submitHandler} />
  }
  return <p>Your name is: {name}</p>

  function submitHandler(e) {
    setName(e.value)
  }
}

and NameTaker.js

import React from 'react';

export default function NameTaker(props) {
  return(
    <div>
      <p>Please enter your name.</p>
      <form onSubmit={props.onSubmit}>
        <label>
          Name:
          <input type='text' name='name' />
        </label>
        <button type='submit'>Submit</button>
      </form>
    </div>
  )
}

This is the render statement in index.js:

ReactDOM.render(
  <React.StrictMode>
    <App />
  </React.StrictMode>,
  document.getElementById('root')
);

The application runs ok locally and the all the elements in NameTaker.js display correctly on the webpage.

When I fill out a name and click the button, I expect it to execute the callback function, store the name string inside the name variable, then when the App function component re-renders, the new name should be stored and <p>Your name is: {name}</p> should get returned instead of the form when the conditional statement is hit. But instead, when I click the button, the URL just changes to add /?name=whatever on the end, and the form remains on the page.

I tried modifying the program so that it gives the callback to the button instead of the form like this: <button onClick={props.onSubmit}>Submit</button> but there is not change in behaviour.

I tried adding e.preventDefault(); before and then after the setName call in my callback function but that didn't work either.

The exact behaviour I'm looking for is: when name is null, return component displaying a form/input box, use callback to save the submitted name in state of the parent component, re-render parent component, but because state is no longer null return the paragraph displaying name instead of the form component.

Can anyone show me how to do that please?

like image 588
C. Ball Avatar asked Sep 06 '25 03:09

C. Ball


1 Answers

You just need to modify your submitHandler function as follows:

  function submitHandler(e) {
    e.preventDefault();
    setName(e.currentTarget.name.value)
  }

You need e.preventDefault() to stop the page from re-rendering, though often it isn't as needed as it used to be, I'm not entirely sure why.

In order to get values from the form, you have to specify which values you want. e.currentTarget.name.value gives you the current target (i.e. the form) then the .name part gives you the input of the form with the name or id of name, and then you can get the value of that input.

const {useState} = React;
function NameTaker(props) {
  return(
    <div>
      <p>Please enter your name.</p>
      <form onSubmit={props.onSubmit}>
        <label>
          Name:
          <input type='text' name='name' />
        </label>
        <button type='submit'>Submit</button>
      </form>
    </div>
  )
}

function App() {
  const [name, setName] = useState(null);
  function submitHandler(e) {
    e.preventDefault();
    setName(e.currentTarget.name.value)
  }
  if (name == null) {
    return <NameTaker onSubmit={submitHandler} />
  }
  return <p>Your name is: {name}</p>


}

ReactDOM.render(
  <React.StrictMode>
    <App />
  </React.StrictMode>,
  document.getElementById('root')
);
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.13.1/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.13.1/umd/react-dom.production.min.js"></script>

<div id="root"/>
like image 138
Zachary Haber Avatar answered Sep 07 '25 23:09

Zachary Haber