Handling Inputs with Same Name in ReactJS - Kevin Uriel Fonseca


JavaScript logo input

Intro

I’m currently working on a form with an input that takes an array to be sent to my DB connection. However, said array is being handled by – checkbox – inputs.

The array needs to look as below in order to work as expected:

{  "tags": ['html', 'css', 'javascript', 'and-so-on']}

That being said, ReactJS does not handle html the way most of us grew up with. In fact, ReactJS has its event handlers names strictly following a name convention created by the Facebook team(I’d like to assume that); an example of an old html input might be exactly like this <input name="title" value="Untitled" type="text" onchange={} onclick={} />, where a React input looks similar but its not the same <input name="title" defaultValue="Untitled" type="text" onChange={} onClick={} />. The difference? the capitalization of some words which in fact helped me solve a problem I’ve seen a lot of people struggle with. That is the use of checkboxes and similar inputs.

Scenario

Let’s say you have a column in your SQL or a field in your Model that takes an array of strings. A good name for it might be “tags”; let’s assume it exists and its found within our DB logic.

Moreover, we already have a list of hard-coded tags that we can use. This forcing us to use either a select element with its multiple attribute or several checkbox inputs to make it easier to spot!. I’ll choose the input checkbox route.

In PHP, when dealing with these inputs, you do something similar to the code below:

<input name="tags[]" value="html" /><input name="tags[]" value="css" /><input name="tags[]" value="javascript" /><input name="tags[]" value="and-so-on" /><?php $POST = ['tags' => ['html', 'css', 'javascript', 'and-so-on']]; ?>

In a simple and dreamy world, where technology does not evolve, this would work perfectly.

However, ReactJS overrides the previous value by default with the newest one; what I mean by this is that if you select the html input and then you select the css input, the state will only get css (in our case).

const [values, setValues] = useState({  tags: []});<input name="tags[]" defaultValue="html" onChange={(e) => {  setValues({    ...values.tags,    tags: e.target.value  })}}  />  <input name="tags[]" defaultValue="css" onChange={(e) => {  setValues({    ...values.tags,    tags: e.target.value  })}}  />  <input name="tags[]" defaultValue="javascript" onChange={(e) => {  setValues({    ...values.tags,    tags: e.target.value  })}}  />

Although we use the ... operand to let JavaScript know that we still need the previous state (…values.tags), the code above simply DOES NOT WORK!

The Solution

What do we do then? Well, apart from having a strict name convention, React is plain JavaScript, we can use ES6 methods and so on. Since I could not simply get the multiple values, I decided to use both the Array.from() & the formData.getAll() methods and it made it work flawlessly! Take a look into it:

const { revalidatePath } from 'next/navigation';const url = 'http://localhost:5000/api/v1/posts';const formSubmit = async (formData) => {  "use server";  const rawFormData = {    title: formData.get('title'),    tags: Array.from(formData.getAll("tags"))  };  await axios.post(url, rawFormData);  revalidatePath(`/posts`)}return (<form action={formSubmit}>  <input type="text" name="title" defaultValue="" />  <input type="checkbox" name="tags" defaultValue="html" />  <input type="checkbox" name="tags" defaultValue="css" />  <input type="checkbox" name="tags" defaultValue="javascript" /></form>)

This will in fact retrieve the input values properly. Thanks for reading!

Remember to read my previous post by clicking here!

SIDEBAR
FOOTER