Didi
Didi

Reputation: 461

Render Input and Dropdown Value in same DIV using UseState

i am working on an App that has an input field and a dropdown. The input field is for the event title and the dropdown has options for the type of event. When I click submit, I want to submit the value of both the event title and the selected dropdown value and render both as one list as I have in the images below.

But when I submit, only the event title is rendered. How can I include the event type too? Can I save the value of the selected dropdown in same array as the event title? Here's my code below:

EventListForm.jsx

import React from "react";
import { v4 as uuidv4 } from "uuid";

const EventListForm = ({
  newEvent,
  setNewEvent,
  events,
  setEventList,
}) => {

  const handleInputChange = (event) => {
    setNewEvent(event.target.value);
  };

  const submitEvent = (event) => {
    event.preventDefault();
    setEventList([...events, { id: uuidv4(), title: newEvent, type: newEvent}]);
  };

  return (
    <form>
      <div>
        <input
          type="text"
          placeholder="Event title"
          onChange={handleInputChange}
        />
      </div>
      <select onChange={handleInputChange}>
          <option value="Birthday">Option 1</option> {" "}
        <option value="Graduation">Option 2</option>
      </select>
      <div>
        <button
          type="submit"
          onClick={submitEvent}
        >
          Submit
        </button>
      </div>
    </form>
  );
};

export default EventListForm;

EventList.jsx

import React from "react";

const EventList = ({ events, setEventList}) => {
  return (
    <div>
      {events.map((event) => (
        <li key={event.id}>
          <input
            type="text"
            value={event.title}
            value={event.type}
            onChange={(event) => event.preventDefault()}
          />
        </li>
      ))}
    </div>
  );
};
export default EventList;

Events.js

import React, {useState } from "react";
import EventListForm from "./EventForm";
import EventList from "./EventList";

const EventReminder = () => {
  const [newEvent, setNewEvent] = useState("");
  const [events, setEventList] = useState([]);

  return (
    <div>
      <div>
        <div>
          <Header />
        </div>
        <div>
          <EventListForm
            newEvent={newEvent}
            setNewEvent={setNewEvent}
            events={events}
            setEventList={setEventList}
          />
        </div>
        <div>
          <EventList events={events} setEventList={setEventList} />
        </div>
      </div>
    </div>
  );
};
export default EventReminder;

Upvotes: 1

Views: 891

Answers (2)

adsy
adsy

Reputation: 11427

There's some stuff to clean up here:

  • The form state of EventListForm really should be local to that component. There is no need for it to be higher up, it overcomplicates and is over-scoping.
  • The form shouldn't really directly edit the event list state, instead it should pass up the event and do the merging in the parent (makes more sense to keep the concerns there).
  • The state merge needs to use the callback form of setState or you can get weird bugs when deriving state from a previous value.
  • You shouldn't use a click handler on submit button. Use onSubmit instead, so it will work properly when pressing enter etc.
import React from "react";

const EventListForm = ({
  onSubmit
}) => {
  const [title, setTitle] = useState("")
  const [type, setType] = useState("")



  return (
    <form onSubmit={(e) => {
        e.preventDefault()
        onSubmit({title, type})
    }>
      <div>
        <input
          type="text"
          placeholder="Event title"
          value={title}
          onChange={(e) => setTitle(e.target.value)}
        />
      </div>
      <select onChange={(e) => setType(e.target.value)}>
          <option selected={type == "Birthday"} value="Birthday">Option 1</option> {" "}
        <option selected={type == "Graduation"} value="Graduation">Option 2</option>
      </select>
      <div>
        <button
          type="submit"
        >
          Submit
        </button>
      </div>
    </form>
  );
};

export default EventListForm;

import React, {useState } from "react";
import EventListForm from "./EventForm";
import EventList from "./EventList";
import { v4 as uuidv4 } from "uuid";

const EventReminder = () => {
  const [events, setEventList] = useState([]);

  return (
    <div>
      <div>
        <div>
          <Header />
        </div>
        <div>
          <EventListForm
            onSubmit={(event) => setEventList(prevEvents=> [...prevEvents, {id: uuidv4(), ...event}])}
          />
        </div>
        <div>
          <EventList events={events} setEventList={setEventList} />
        </div>
      </div>
    </div>
  );
};
export default EventReminder;
import React from "react";

const EventList = ({ events}) => {
  return (
    <div>
      {events.map((event) => (
        <li key={event.id}>
          <input
            type="text"
            value={event.title}
            disabled
          />
      <select disabled name="type">
          <option value="Birthday" selected={event.type === "Birthday"}>Option 1</option>
        <option value="Graduation" selected={event.type === "Graduation"}>Option 2</option>
      </select>
        </li>
      ))}
    </div>
  );
};
export default EventList;

Upvotes: 1

Haim Abeles
Haim Abeles

Reputation: 1021

This is happening to you because you are currently overriding the same state of newEvent in each of the input fields, I corrected your code by changing the value of newEvent to an object that contains a key for title and for type (note that I added a name attribute in the inputs, and when submitting the form takes for each of the values the appropriate value from the state

  const handleInputChange = (event) => {
    setNewEvent({ [event.currentTarget.name]: event.target.value });
  };

  const submitEvent = (event) => {
    event.preventDefault();
    setEventList([...events, { id: uuidv4(), title: newEvent.title, type: newEvent.type}]);
  };

  return (
    <form>
      <div>
        <input
          type="text"
          name="title"
          placeholder="Event title"
          onChange={handleInputChange}
        />
      </div>
      <select onChange={handleInputChange} name="type">
          <option value="Birthday">Option 1</option> {" "}
        <option value="Graduation">Option 2</option>
      </select>
      <div>
        <button
          type="submit"
          onClick={submitEvent}
        >
          Submit
        </button>
      </div>
    </form>
  );
};

Upvotes: 0

Related Questions