Home > OS >  Why is the text inside my select box only changing when more select boxes are added?
Why is the text inside my select box only changing when more select boxes are added?

Time:11-27

I am trying to make a form in next.js with select boxes from material UI, with a different number of select boxes based on user input, but when I change the value inside a select box, it does not update the text displayed, and only does so when I add another pair of select boxes. Here's my code:

import {
  ChangeEventHandler,
  ReactElement,
  useContext,
  useEffect,
  useState,
} from "react";
import { NextPageWithLayout } from "../../../utils/types";
import styles from "./index.module.scss";
import * as React from "react";
import MenuItem from "@mui/material/MenuItem";
import FormControl from "@mui/material/FormControl";
import Select, { SelectChangeEvent } from "@mui/material/Select";
import { ThemeProvider, createTheme } from "@mui/material/styles";

const DashboardPage: NextPageWithLayout = () => {

  const [users, setUsers] = React.useState(["none"]);
  const [tzValues, setTzs] = React.useState(["none"]);
  const [selects, changeSelects] = useState(1);

  const handleChangeUser = (event: SelectChangeEvent, i:number) => {
    var tempUsers = users;
    if (tempUsers[i] == undefined) {tempUsers.push(event.target.value)}
    else {tempUsers[i] = event.target.value}
    setUsers(tempUsers);
    console.log(users)
  };

  const handleChangeTz = (event: SelectChangeEvent, i:number) => {
    var tempTz = tzValues;
    if (tempTz[i] == undefined) {tempTz.push(event.target.value)}
    else {tempTz[i] = event.target.value}
    setTzs(tempTz);
    console.log(tzValues)
  };

  const submit = (event: any) => {
    // irrelevant to the question
  };

  var options = ["test1", "test2", "test3"];

  const darkTheme = createTheme({
    palette: {
      mode: "dark",
    },
  });

  const addSelect = function () {
    let tempTz = tzValues
    tempTz.push("");
    setTzs(tempTz);
    let tempUsers = users
    tempUsers.push("none")
    setUsers(tempUsers);
    changeSelects(selects   1);
  };

  return (
    <div className="page">
      <form onSubmit={submit} className={styles.stuff}>
        <div className={styles.times} id="times" style={{ display: "none" }}>
          <ThemeProvider theme={darkTheme}>
            {[...Array(selects)].map((e, i) => (
              <div key={i} className={styles.selectContainer}>
                <FormControl sx={{ m: 1, minWidth: 80 }}>
                  <Select
                    id={"selectUser" i}
                    defaultValue={users[i] || "none"}
                    onChange={(ev) => handleChangeUser(ev, i)}
                    autoWidth
                    MenuProps={{ PaperProps: { sx: { maxHeight: 200 } } }}
                  >
                    <MenuItem value="none" selected>
                      <em>None</em>
                    </MenuItem>
                    {options.map((option) => (
                      <MenuItem value={option} key={Math.random()}>
                        {option}
                      </MenuItem>
                    ))}
                  </Select>
                </FormControl>
                <FormControl sx={{ m: 1, minWidth: 80 }}>
                  <Select
                    id={"selectZone" i}
                    defaultValue={tzValues[i] || "none"}
                    onChange={(ev)=>handleChangeTz(ev,i)}
                    autoWidth
                    MenuProps={{ PaperProps: { sx: { maxHeight: 200 } } }}
                  >
                    <MenuItem value="none" selected>
                      <em>None</em>
                    </MenuItem>
                    {["-12","-11","-10","-9","-8","-7","-6","-5","-4","-3","-2","-1"," 0"," 1"," 2"," 3"," 4"," 5"," 6"," 7"," 8"," 9"," 10"," 11"," 12",].map((option) => (
                      <MenuItem value={option} key={Math.random()}>
                        GMT{option}
                      </MenuItem>
                    ))}
                  </Select>
                </FormControl>
                <button type="button" className={styles.addtz} onClick={addSelect}>
                   
                </button>
                <br />
              </div>
            ))}
          </ThemeProvider>
        </div>
        <div>
          <button className={styles.save}>Save</button>
        </div>
      </form>
    </div>
  );
};

export default DashboardPage;

I tried using defaultValue intead of value and although it fixed the issue, it kept throwing warnings into the console because defaultValue is only supposed to be used for uncontrolled inputs, and I need this to be controlled, I tried manually assigning the text in the change handlers, but when I add new select boxes, it tries deleting the old text, which isn't there anymore, I tried getting rid of the button, but that just made it so there was no way to update the select box text no matter what, and I tried making it remove and add back a select box when the value is changed in the hopes it would update it, but although it did update, it would only remove one or only add one, depending on which statement came first

CodePudding user response:

When you declare tempUsers and tempTz it's not a new array, but you still mutate the users and tzValues states directly, and this's not allowed.

From React docs:

state is a reference to the component state at the time the change is being applied. It should not be directly mutated. Instead, changes should be represented by building a new object based on the input from state.

You can declare new array variable based on old state :
let tempUsers = [...users]
let tempTz = [...tzValues]

const handleChangeUser = (event: SelectChangeEvent, i: number) => {
    var tempUsers = [...users];      // <== Here
    .....
};
const handleChangeTz = (event: SelectChangeEvent, i: number) => {
    var tempTz = [...tzValues];      // <== Here
    ........
};
  • Related